【发布时间】:2015-03-05 01:37:29
【问题描述】:
我用 C++ 编写了一个匿名阶乘函数,并用 g++4.9.2 编译了我的代码。 它运作良好。但是,我不知道我的函数的类型。
#include<iostream>
#include<functional>
using std::function;
int main()
{
//tested at g++ 4.9.2
//g++ -std=c++1y -o anony anony.cpp
auto fac = [](auto self,auto n)->auto{
if(n < 1)
return 1;
else
return n * self(self,n-1);
};
std::cout<<fac(fac,3)<<std::endl;//6
return 0;
}
那么,我想知道:fac 和 self 的类型是什么?
如果我只是将 C++ 代码翻译成 Haskell,它将无法编译,因为
它涉及无限类型:
fac2 self 0 = 1
fac2 self n = n * (self self $ n-1)
我必须围绕它定义一些递归类型的工作:
data Y a = Y ((Y a)->a->a)
fac2 self 0 = 1
fac2 self n = n * ((applY self self) (n-1))
where applY (Y f1) f2 = f1 f2
fact2 = fac2 $ Y fac2
那么,为什么 g++ 能得到完全正确的 fac 函数类型,而 g++ 认为 fac 函数是什么类型呢?
【问题讨论】:
-
当您将
auto替换为某种类型时,例如int编译器应该告诉你它不能推断类型并给它们命名。但我没有测试过 -
fac这是一个通用的 lambda,它的作用就像一个带有模板化operator()的函子。请注意,这些对于 c++14 来说是新的。 -
附带说明,编写 Haskell 版本的更好方法是将其拆分为递归位(即一般情况下,
fix :: (a -> a) -> a和fix f = f (fix f))和非递归位。非递归位是fact1 recur n = if n == 0 then 1 else n * recur (n-1),您会注意到(a)不是递归的,(b)具有有限且可推断的类型fact1 :: (Int -> Int) -> (Int -> Int),并且(c)实现了一个阶乘的单个“步骤”。然后我们通过组合递归和非递归位来“完成”它:fact = fix fact1. -
好吧,我不会称
fix为 Y 组合子。它具有相同的效果,但有许多定点组合器,其中Y和fix只是两个示例。 -
哦,是的,我现在记起来了:
Data.Function中的定义使fix (1:)成为循环链表而不是无限链表,对于其他一些类似的事情也是如此。它可以让您将数据结构打结成结,而更明显的fix f = f (fix f)则不会。
标签: c++ haskell types c++14 generic-lambda