Functional programming D中的Y-组合子?

Functional programming D中的Y-组合子?,functional-programming,d,lambda-calculus,y-combinator,Functional Programming,D,Lambda Calculus,Y Combinator,我试图更好地学习Y-combinator(我在Scheme中有点理解它),并在D2.0中实现它,但我失败得很惨: auto fact = delegate(uint delegate(uint) recurse) { return delegate(uint n) { return n > 1 ? n * recurse(n - 1) : 1; }; }; fact(fact)(5); 这不起作用,原因很明显,我无法将事实传递到事实(它的类型是什

我试图更好地学习Y-combinator(我在Scheme中有点理解它),并在D2.0中实现它,但我失败得很惨:

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

fact(fact)(5);
这不起作用,原因很明显,我无法将
事实
传递到
事实
(它的类型是什么?)。此外,我仍然需要将
事实
的名称传递给它自己,这样它就不会工作了,对吗


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

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

其他语言的一些示例:

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

  • 在OCaml中,可以添加一个封装函数类型的变量类型。同样,这允许分离类型,因此类型递归是可能的


如果您想从其他语言中获得一些示例,请查看。

请参阅详细的解释。

这是D(和C/C++)的一个已知限制,即处理类型化自引用的函数无法声明(上次我检查时)


我觉得这很讽刺,因为它相当于语法的限制(函数原型的长度是无限的)或命名约定(相同的问题,但名称有误)而不是语义或体系结构的限制。

我的通用Y组合符在D:

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)));
}
导入std.stdio、std.algorithm、std.range;
自动Y(R,T…)(R代表(T)代表(R代表(T))f){
结构F{R委托(F,T)F;};
return(R delegate(T)delegate(F)a){return a(F((F b,ti){return F(a(b))(i)});
}((fb){return(tn){return b.F(b,n);};});
}
void main(){
自阶乘=Y((长委托(长)自){return(长i){return i?自(i-1)*i:1;};});

auto fibonacci=Y((int delegate(int)self){return(int i){return idelegates已经是引用类型,您可以删除
&
@BCS:Good point,它最初是一个方法,我忘了删除它。将修复:)似乎是D缺少的关键功能(与C#相比)是否能够在签名本身中使用委托别名…RosettaCode的示例代码可以工作,因此可以公平地说D缺少一个关键功能?RosettaCode的示例代码使用类型转换来避免难看的问题。可以将委托包装在结构中,因为结构中可以包含其类型为的成员递归地依赖于结构类型。但是Mehrdad有一点:别名声明目前比必要的更为有限,因为编译器不允许大多数形式的别名递归。(例如:struct Foo(T){Bar*qux;}alias Foo!int Bar;//compile error struct Foo(T){.Foo!int*qux;}//works+1是的,这有点傻,我当时真的很困惑,试图把我的大脑围绕着如何将函数传递给它自己。你知道他们是否计划解决这个问题吗?(例如,
void foo(typeof(foo)){}
给出了一个
正向引用
错误。)@Mahrdad:据我所知并非如此。一个围绕该项的简单结构包装器解决了这个问题。顺便说一句,Haskell也没有做到这一点,比如说
“不能声明无限长的类型”