大神Bartosz Milewski在2009年写了一篇文章《What Does Haskell Have to Do with C++?》,使用C++实现Haskell函数式编程语言的一些特性。【传送门在文末】
其中有这样一段例子:
// code 1
1.templateclassfact{
2.public:
3.staticconstintvalue=n*fact::value;
4.};
5.
6.templateclassfact{// specialization for n = 0
7.public:
8.staticconstintvalue=1;
9.};
注:原文中使用的是struct关键字,这里改为class并加上了public
我猜,你没看懂。没关系,我们先跳过上面这一段有着【令人恐怖的语法】的C++模版代码。
上面的例子想干嘛呢?其实它只是想计算n的阶乘。
如果你在C语言里面学过递归,应该知道下面这段计算阶乘的递归函数
// code 2
intfact(intn){
if(==n)
return1;//0阶问题答案。0!等于1
else
return(n*fact(n-1));//问题降阶:n阶->n-1阶
}
它的效果就等于下面的代码
// code 3
intfact2(intn){ // 用 for 循环计算阶乘
intp=1;
for(inti=n;i>=1;i--)
p*=i;
returnp;
}
那么,第一段代码(code1)与第二段代码(code2)的区别在哪里呢?
区别在于,code1是在编译时(由编译器)计算的,code2是在运行时(就是代码运行的时候)计算的。
现在来解释一下code1(部分根据Bartosz Milewski文中的说法)
// code 1
/*第1行代码声明了一个类模版fact。
这个模版接受一个“非类型参数”n,
n是整数。
*/
1.templateclassfact{
2.public:
/*第3行代码声明了一个静态整型常量
成员value。而value的值是使用
递归模版表示的
*/
3.staticconstintvalue=n*fact::value;
4.};
5.
/*第6行代码是“特化”类模版fact,
也就是显式地给出某种类型参数的
类模板的一个实例的代码,而非由
编译器生成。
在这里,是给出了参数n为时模板
fact的代码。这样,编译器不会再
根据类模版fact生成n=0时的代码
关于模版特化,详见文末链接
*/
6.templateclassfact{// specialization for n = 0
7.public:
8.static const intvalue =1;
9.};
/*根据C++规范,模版特化的代码必须
放到模版声明之后。
因此上面的代码看上去好像先处理了
由n阶到n-1阶的降阶问题,然后再给
出了阶的解答
这可不像code2。code2中有if/else,
因此可以把降阶代码与阶解答代码调
换先后次序(当然if条件得改)。
*/
那么这个用模版计算阶乘的代码(类?)该怎么用呢?如下:
cout::value
其中,C++编译器会为“fact::value”这个调用匹配最合适的模版代码,也就是code1中的第6-9行代码。
如果用非零参数调用呢?
cout::value
其中,C++编译器会为“fact::value”这个调用匹配code1中的第1-4行代码。
前面blahblhaaaaaaaaaaaah讲了一大堆,其实都不是正经事儿。
正经是下面的Haskell代码:
//code 4
1.fact=1
2.fact n=n*fact(n-1)
上面两行代码定义了函数fact。fact是函数名,fact的后面、等号的前面是函数的参数。等号后面是函数体,函数体的计算结果就是fact函数的返回值。
当程序员调用【fact 8】的时候(参数是8,因为Haskell函数调用一般不像C++那样给参数加括号),Haskell会将之匹配到上面代码的第2行。这种参数匹配,是Haskell特有的函数声明与调用方式。
所以前面的code1中C++模版代码,就是在模仿code4中的Haskell代码。
下面给出一个完整的Haskell程序
moduleFactwhere
importSystem.IO
fact::Integer->Integer
fact=1
factn=n*fact (n-1)
main::IO()
main=do
putStrLn$"8! = "++ show (fact 8)
putStrLn$"88! = "++ show (fact 88)
上面的代码输出结果是:
8! = 40320
88! =185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000
Haskell对C++说:我能算88!,你行吗?
C++说:你欺负人!
Bartosz Milewski文章《What Does Haskell Have to Do with C++?》的传送门:
短网址:http://t.cn/Rg6yxeW
原网址:https://bartoszmilewski.com/2009/10/21/what-does-haskell-have-to-do-with-c/
模版特化:
在百度百科中搜索“模版特化”
链接:https://baike.baidu.com/item/%E6%A8%A1%E6%9D%BF%E7%89%B9%E5%8C%96
领取专属 10元无门槛券
私享最新 技术干货