C++模版编程实现Haskell的函数模式匹配特性[图]:大神 Bartosz Milewski 在2009年写了一篇文章《What Does Haskell Have to Do with C++?》,使用C++实现Haskell函数式编程语言的一些特性。【传送门在文末】其中有这样一段例子:// code 11.templateclass fact {2.public:3. staticconstint value = n * fact::value;4.};5.6.templateclass fact{// specialization for n = 07.public:8. staticconstint value =1;9.};注:原文中使用的是struct关键字,这里改为class并加上了public我猜,你没看懂。没关系,我们先跳过上面这一段有着【令人恐怖的语法】的C++模版代码。上面的例子想干嘛呢?其实它只是想计算n的阶乘。如果你在C语言里面学过递归,应该知道下面这段计算阶乘的递归函数// code 2int fact(int n){if(0== n )return1; //0阶问题答案。0! 等于1elsereturn( n * fact( n -1)); //问题降阶:n阶->n-1阶}它的效果就等于下面的代码// code 3int fact2(int n){ // 用 for 循环计算阶乘int p =1;for(int i=n; i >=1; i--) p *= i;return p;}那么,第一段代码(code1)与第二段代码(code2)的区别在哪里呢?区别在于,code1是在编译时(由编译器)计算的,code2是在运行时(就是代码运行的时候)计算的。现在来解释一下code1 (部分根据Bartosz Milewski文中的说法)// code 1/* 第1行代码声明了一个类模版 fact。这个模版接受一个“非类型参数”n,n是整数。*/1.templateclass fact {2.public:/* 第3行代码声明了一个静态整型常量成员 value。而 value 的值是使用递归模版表示的*/3. staticconstint value = n * fact::value;4.};5./* 第6行代码是“特化”类模版fact,也就是显式地给出某种类型参数的类模板的一个实例的代码,而非由编译器生成。在这里,是给出了参数n为0时模板fact的代码。这样,编译器不会再根据类模版fact生成n=0时的代码关于模版特化,详见文末链接*/6.templateclass fact{// specialization for n = 07.public:8. static const int value = 1;9. };/* 根据C++规范,模版特化的代码必须放到模版声明之后。因此上面的代码看上去好像先处理了由n阶到n-1阶的降阶问题,然后再给出了0阶的解答这可不像code2。code2中有if/else,因此可以把降阶代码与0阶解答代码调换先后次序(当然if条件得改)。*/那么这个用模版计算阶乘的代码(类?)该怎么用呢?如下: cout ::value其中,C++编译器会为“fact::value”这个调用匹配最合适的模版代码,也就是code1中的第6-9行代码。如果用非零参数调用呢?cout ::value其中,C++编译器会为“fact::value”这个调用匹配code1中的第1-4行代码。前面blahblhaaaaaaaaaaaah讲了一大堆,其实都不是正经事儿。正经是下面的Haskell代码://code 41. fact 0=12. fact n = n * fact (n -1)上面两行代码定义了函数fact。fact是函数名,fact的后面、等号的前面是函数的参数。等号后面是函数体,函数体的计算结果就是fact函数的返回值。当程序员调用【fact 8】的时候(参数是8,因为Haskell函数调用一般不像C++那样给参数加括号),Haskell会将之匹配到上面代码的第2行。谁动了我的奶酪读书笔记摘抄好词好句及感悟赏析,这种参数匹配,是Haskell特有的函数声明与调用方式。所以前面的code1中C++模版代码,就是在模仿 code4 中的Haskell代码。下面给出一个完整的Haskell程序moduleFactwhereimportSystem.IOfact::Integer->Integerfact0=1fact n = n * fact (n-1)main::IO()main=doputStrLn $"8! = "++ show (fact 8)putStrLn $"88! = "++ show (fact 88)上面的代码输出结果是:8! = 4032088! =185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000 Haskell对C++说:我能算88!,你行吗?C++说:你欺负人!