2011-08-04 4 views
8

나는 (내가의 종류의 계획에 이해)와 D 2.0을 구현하는 Y-콤비 더 배우려고 노력하고있어 나는 매우 비참하게 실패하고 있습니다 :D에서 Y- 연결자?

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

fact(fact)(5); 

이하지 않는 작동합니다. factfact (그 유형은 무엇입니까?)에 전달할 수없는 분명한 이유가 있습니다. 그리고 게다가, 나는 여전히 fact의 이름을 전달해야하므로 어쨌든 작동하지 않을 것입니다, 그렇습니까?

하지만 ... D에서 Y-combinator를 구현하려면 어떻게해야합니까?

+0

대리자는 이미 참조 유형이므로 '&'를 삭제할 수 있습니다. – BCS

+0

@BCS : 좋은 점은 원래 방법이었고 제거하는 것을 잊었습니다. 고칠 것입니다. :) – Mehrdad

답변

7

광범위한 설명은 here을 참조하십시오.

+0

D가 부족한 (C#과 비교하여) 서명 자체 내에 대리자 별칭 이름을 사용하는 기능이 부족한 것처럼 보입니다. – Mehrdad

+0

RosettaCode의 예제 코드가 작동하므로 D가 중요하지 않습니다. 특색? – gmfawcett

+1

RosettaCode의 예제 코드는 추악한 문제를 피하기 위해 형식 캐스트를 사용합니다. 구조체가 struct 유형에 대해 재귀 적으로 종속되는 멤버를 가질 수 있기 때문에 대리자를 구조체 내에 래핑하는 것이 가능합니다. 그러나 Mehrdad는 컴파일러가 별칭 재귀의 대부분의 형식을 허용하지 않기 때문에 별칭 선언이 현재 필요한 것보다 더 제한적이라는 점을 지적합니다. (예 : struct Foo (T) {Bar * qux;} 별칭 Foo! int Bar; // 컴파일 오류 struct Foo (T) {. Foo!int * qux;} // works) – tgehr

3

D가 잘 모르지만 대부분의 언어에서는 비 재귀를 구현하려고 할 때 함수 유형에 문제가 발생합니다 (코드에 Y-Combinator가 아직 없음). 타입을 여러 부분으로 분리하고 재귀를 유형으로 분리함으로써 일반적인 방법을 얻을 수 있습니다. 다른 언어

일부 예 : C 하나에

  • 은 일반적으로 함수 포인터를 포함하는 구조체를 기록합니다. 이 구조체는 인수로 사용될 수 있습니다.

  • OCaml에서 함수 유형을 래핑하는 변형 유형을 추가합니다. 이 경우에도 유형을 분리 할 수 ​​있으므로 유형 재귀가 가능합니다.

다른 언어의 예제가 필요하면 this page을보십시오.

4

형식화 된 자체 참조를 다루는 함수가 선언하기가 불가능한 (마지막으로 확인한) D (및 C/C++)의 알려진 제한 사항입니다.

의미 론적이거나 구조적인 것보다 구문의 제한 (함수 프로토 타입의 길이가 무한 함) 또는 명명 규칙 (동일한 문제이지만 이름이 맹 글링 됨)이 있기 때문에이 아이러닉을 찾습니다. D에서

+0

+1 조금 바보 같아서, 내 머리를 감싸는 방법에 대해 혼란스러워지고있었습니다. 그들이 이것을 고칠 계획이라면 어떨까요? (예 :'void foo (typeof (foo)) {}'는'forward reference' 오류를줍니다.) – Mehrdad

+0

@Mahrdad : 내가 아는 것은 아닙니다. OTOH는 항목 주위에 간단한 구조체 래퍼를 사용하여 문제를 해결합니다. – BCS

+0

그런데 하스켈은 또한 "무한한 길이의 타입을 선언 할 수 없습니다" – vines

3

내 일반적인 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)로 해결되고 있습니다.