D中的Y组合子?

时间:2011-08-04 07:44:25

标签: functional-programming d lambda-calculus y-combinator

我正在尝试更好地学习Y-combinator(我中理解它在Scheme中)并在D 2.0中实现它,而且我很失败:

auto fact = delegate(uint delegate(uint) recurse)
{
    return delegate(uint n)
    {
        return n > 1 ? n * recurse(n - 1) : 1;
    };
};

fact(fact)(5);

这不起作用,因为显而易见的原因是我无法将fact传递给fact(它的类型是什么?)。此外,我仍然需要fact的名字传递给自己,所以无论如何它都不会起作用,对吧?

但是......我如何在D中实现Y-combinator?

4 个答案:

答案 0 :(得分:7)

查看详尽的解释here

答案 1 :(得分:4)

D(和C / C ++)的一个已知限制是,处理类型化自引用的函数是不可能的(我上次检查)要声明。

我觉得这很具有讽刺意味,因为它等于语法的限制(函数原型的长度是无限的)或命名约定(同样的问题,但名称是错误的)而不是任何语义或架构。

答案 2 :(得分:3)

我不知道D,但是对于大多数语言,当你尝试实现非递归时,你会遇到函数类型的问题(你的代码中还没有Y-Combinator)。通常的方法是通过将类型分成几个部分来实现,这样就可以将递归转换为类型。

其他语言的一些例子:

  • 在C中,通常会编写一个包含函数指针的结构。然后可以将此结构用作参数。

  • 在OCaml中,会添加一个包含函数类型的变体类型。同样,这允许分离类型,因此可以进行类型递归。

如果您想要其他语言的示例,请查看this page

答案 3 :(得分:3)

我在D中的通用Y组合器:

import std.stdio, std.algorithm, std.range;
auto Y(R,T...)(R delegate(T) delegate (R delegate(T)) f){
    struct F{R delegate(F,T) f;};
    return (R delegate(T)delegate(F) a){return a(F((F b,T i){return f(a(b))(i);}));
    }((F b){return (T n){return b.f(b,n);};});
}
void main(){
    auto factorial=Y((long delegate(long) self){return (long i){return i?self(i-1)*i:1;};});
    auto fibonacci=Y((int delegate(int) self){return (int i){return i<2?i:self(i-1)+self(i-2);};});
    auto ackermann=Y((long delegate(long,long) self){return (long n,long m){return n?m?self(n-1,self(n,m-1)):self(n-1,1):m+1;};});
    writeln(map!factorial(iota(0,20)));
    writeln(map!fibonacci(iota(0,20)));
    writeln(map!((a){return ackermann(a%4,a/4);})(iota(0,20)));
}

我从一个简单的阶乘函数的递归定义开始,并修改它直到我的代码看起来像这样。无限类型问题正在使用类型包装器(struct F)。