Functional Programming與C++的模板元編程

來源:互聯網
上載者:User
先來看一個例子:#include <stdio.h>
template <int depth>
class Fibnacci
{
public:
    static const int value = Fibnacci<depth-1>::value + Fibnacci<depth-2>::value;
};

template <>
class Fibnacci<0>
{
public:
    static const int value = 0;
};

template <>
class Fibnacci<1>
{
public:
    static const int value = 1;
};

template <int depth>
void printFibnacci()
{
    printFibnacci<depth-1>();
    wprintf(L"%d\n", Fibnacci<depth>::value);
}

template <>
void printFibnacci<0>()
{
    wprintf(L"%d\n", Fibnacci<0>::value);
}

int main()
{
    printFibnacci<8>();
    return 0;
}

Fibnacci數列,相信是個程式員都能寫出來,重點是,這個Fibnacci數列的計算完全是在編譯時間完成!後面的print也是如此,當你把參數調得很大時,已耗用時間不會有任何改變,但是你會花費長時間在編譯階段。
如果你聽說過一些模板元編程,你一定會知道"C++模板是圖靈完備的"這個說法。模板元是如何圖靈完備的?答案是,模板元跟Functional原理是一樣的。
模板的本質是定義與替換,lambda函數的本質也是定義與替換,這裡的替換實際上符合的是數學中的lambda演算理論:

Lambda演算

λ演算lambda calculus)是一套用於研究函數定義、函數應用和遞迴的形式系統。它由丘奇(Alonzo Church)和他的學生克萊尼(Stephen Cole Kleene)在20世紀30年代引入。Church 運用λ演算在1936年給出判定性問題(Entscheidungsproblem)的一個否定的答案。這種演算可以用來清晰地定義什麼是一個可計算函數。關於兩個 lambda 演算運算式是否等價的命題無法通過一個“通用的演算法”來解決,這是不可判定效能夠證明的頭一個問題,甚至還在停機問題之先。Lambda 演算對函數式程式設計語言有巨大的影響,比如 Lisp 語言、ML 語言和 Haskell 語言。

Lambda 演算可以被稱為最小的通用程式設計語言。它包括一條變換規則(變數替換)和一條函數定義方式,Lambda 演算之通用在於,任何一個可計算函數都能用這種形式來表達和求值。因而,它是等價於圖靈機的。儘管如此,Lambda 演算強調的是變換規則的運用,而非實現它們的具體機器。可以認為這是一種更接近軟體而非硬體的方式。v

所以C++的模板元編程實際上屬於函數式風格編程,這也是很多C++程式員覺得它不舒服的原因。

另外說一點,所謂圖靈完備的語言,則必定可以用它來表達任何演算法,那麼我們現在使用的這個直接Fibnacci是一個非常低效的演算法。
有一個常見的說法"Fibnacci的迭代演算法比遞迴演算法快",這裡我想強調,遞迴只是形式,與演算法無關,下面奉上O(n)的Fibnacci演算法(這回就不那麼折磨編譯器了):#include <stdio.h>
template <int depth>
class Fibnacci
{
public:
    static const int value = Fibnacci<depth-1>::value + Fibnacci<depth-1>::last;
    static const int last = Fibnacci<depth-1>::value ;
};

template <>
class Fibnacci<0>
{
public:
    static const int value = 0;
};

template <>
class Fibnacci<1>
{
public:
    static const int value = 1;
    static const int last = 0;
};

template <int depth>
void printFibnacci()
{
    printFibnacci<depth-1>();
    wprintf(L"%d\n", Fibnacci<depth>::value);
}

template <>
void printFibnacci<0>()
{
    wprintf(L"%d\n", Fibnacci<0>::value);
}

int main()
{
    printFibnacci<8>();
    return 0;
}

最後留一道題目,各位看官如果有興趣,可以做做,回複在下面或者留下連結均可,用C++模板或C#lambda函數都可以:
1994年的一次會議上,Erwin Unruh寫了一個程式,在編譯錯誤裡面列印出一個素數序列。這個程式當時震驚了當時在場的包括C++之父Bjarne Stroustrup在內的幾位大師,這個事情正標誌了C++模板系統的圖靈完備性被發現。那麼,讓我們也來向先輩致敬,來實現這個列印出一個素數序列的模板吧!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.