2011-06-13 6 views
18

저는 D를 처음 접했고, 하스켈과 같은 타입 클래스로 프로그래밍하는 좋은 방법을 찾고 있습니다. Functor, Monoids 등 D.D의 형질을 유형 클래스에 사용할 수 있습니까?

Tango 또는 Phobos에서 구현 된 것입니까?

특정 속성에 대해 컴파일 타임 유형 검사를 사용할 수있는 특성에 대해 들어 봤습니다. 유형 수업에 사용할 수 있습니까?

나는 템플릿 특수화와 약간의 노력이 함께 왔어요 :

// Monoid.d 
// generic Monoid gets called when there is no instance of Monoid for Type T 
class Monoid(T) { 
    pragma(msg, "Type is not a Monoid"); 
} 

// Monoid instance for double 
class Monoid(T:double) { 
    static T mzero() { return 0; } 
    static T mappend(T a, T b) { return a + b;} 
} 

// Monoid instance for int 
class Monoid(T:int) { 
    static T mzero() { return 0; } 
    static T mappend(T a, T b) { return a + b;} 
} 

유형이 매개 변수 모노 이드 할 필요가 다음과 같이 표현 될 수있는 일반적인 알고리즘 :

template genericfunctions() { 
    T TestMonoid(T,N = Monoid!T)(T a) { 
     return N.mappend(N.mzero(),a); 
    } 
} 

그러나 템플릿 매개 변수를 생략하려면 필요한 모든 Monoid 인스턴스를 가져 와서 genericfunctions 템플릿을 혼합해야합니다.

import Monoid; 
import std.stdio; 
import std.conv; 
mixin genericfunctions; 

void main() { 
    writefln(to!string(TestMonoid(3))); 
    writefln(to!string(TestMonoid(3.3243))); 
} 

이제 int 및 double을 Monoids로 사용할 수 있습니다.

당신이 인스턴스 자체가 제네릭은 Functor 같은 종류의 클래스가있을 때 일을 더 복잡 얻을 그러나 :

module Functors; 

// generic Functor like generic Monoid 
class Functor(alias T, A) { 
    pragma(msg,"Not an instance of Functor"); 
} 

// very simple container to demonstrate functors behavior 
class FunctorTest(A) { 
    public A a; 
    this(A a) { 
     this.a = a; 
    } 
} 

// instance of Functor for FunctorTest!A 
class Functor(alias T:FunctorTest,A) { 
    static T!B fmap(B)(T!A a, B delegate(A) fn) { 
     return new T!B(fn(a.a)); 
    } 
} 

한 알고리즘은 다음과 같을 것이다 :

template genericfunctions() { 
    T TestMonoid(T,N = Monoid!T)(T a) { 
     return N.mappend(N.mzero(),a); 
    } 

    // F is the Functor, A the functors type before, 
    // B the functors Type after, N is the instance of Functor 
    F!B fmap(alias F,A,B,N=Functor!(F,A))(F!A a, B delegate(A) fn) { 
     return N.fmap!B(a,fn); 
    } 
} 

을 다행히도을, 당신은 생략 할 수 있습니다 네 가지 템플릿 매개 변수를 사용할 때 :

mixin genericfunctions; 

void main() { 
    auto a = new FunctorTest!int(3); 
    auto b = fmap(a,(int b) {return b+ 0.5;}); 
    writefln(to!string(b.a)); 
} 

하지만 원하는 경우 Type에 대해 다른 Functor 인스턴스를 사용하려면 fmap의 4 가지 유형 매개 변수를 모두 지정해야합니다. 인스턴스를 지정하기 만하면되고 다른 매개 변수는 여기서 추론 할 수있는 방법이 있습니까?

서투른 mixin 대안에 대한 대안이 있습니까?

이 접근법의 다른 단점이 있습니까?

다른 방법은 어떻습니까? 지금까지이 글을 읽고에 대한 생각과 답변 : 시간을내어

감사


편집 :

는 D에서 유닛 테스트와 펑 법 등의 제약 조건을 정의 할 수 있습니까? 매우 좋을거야.

+1

비 FP 언어로 된 순수 FP의 구문을 모방하는 것을 포기하는 것이 더 쉬울 수도 있습니다. 당신이하려는 일에 따라 더 쉬울 수도 있고 그렇지 않을 수도 있습니다. – BCS

+2

D는 다중 패러다임 언어이며 일류 함수와 Paint 함수와 같은 FP를 아주 잘 지원합니다.이 함수는 지금까지 내가 아는 Haskell에서만 발견됩니다. 타입 클래스는 추상화에서 프로그래머를 가능하게하는 매우 강력한 기능입니다. 상속에 대한 장점은 기존 유형에 특성을 추가 할 수 있다는 것입니다. 만약 당신이 Monoid 인터페이스를 가지고 있다면, int를 monoid로 사용할 수도없고 다른 타입을 befor로 만들 수도 없었을 것입니다. 그리고 나는 그것들을 D.로 가질 수 있다고 생각합니다.여기서는 기능 측면에서 구현하기가 어렵지만 발신자 측면에서는 인식하지 못합니다. – KIMA

답변

4
template genericfunctions() { 
    T TestMonoid(T,N = Monoid!T)(T a) { 
    return N.mappend(N.mzero(),a); 
    } 
} 

필요 없음을 그것을 위해 : 충분해야

T TestMonoid(T,N = Monoid!T)(T a) { 
    return N.mappend(N.mzero(),a); 
} 

합니다. 이를 통해 mixin도 필요하지 않습니다.

그것은 D에 유닛 테스트와 펑 법률과 같은 제약을 정의 할 수 있습니까?

없음 완전히 확인 당신이 요구하는 것을 이해하지만 당신은 템플릿 함수/클래스와 제약 조건을 정의 할 수 있습니다 T이 필수 유형 인 경우

void isEven(T)(T x) if (isIntegral!T) { return x % 2 == 0; } 

이 템플릿은 다음 인스턴스화됩니다.

Templates 페이지 하단의 '템플릿 제약 조건'섹션을 참조하십시오.

+1

나는 그것도 충분할 것이라고 생각했다. N을 직접 입력 할 때 작동하지만 컴파일러가 소스 파일에서만 메서드를 정의했기 때문에 컴파일러가 올바른 템플릿을 찾을 수 없습니다. 그러나 제약 팁을 가져 주셔서 감사합니다! 나는 그것을 살펴볼 것입니다 – KIMA

+0

@KIMA : 어떤 DMD 버전을 사용하고 있습니까? 그것은 나를 위해 잘 작동합니다. –

4

당신이 말한 것을 이해해야하므로 질문에 대답하는 것이 아닙니다. 저는 여러분이 사용하고있는 D와 여러분에게 유용 할 수있는 것들에 대해서 이야기하려고합니다.

D에는 유형 클래스가 없습니다 (아시다시피). 대신 유형 지정 (사용중인)과 template constraints이 있습니다. 유형 전문화는 템플리트 제약 조건 이전에 왔으며 실제로 거기에서 사용될 수 있습니다.

템플릿 제약 조건을 사용하면 유형의 특정 속성을 요구할 수 있습니다. 이것은 std.range에서 많이 사용되는 것을 알 수 있으며 std.traits에 이러한 제약 조건을 작성하는 데 도움이되는 템플릿이 있습니다. 나는 더 복잡한 예제를 할 수 있지만 지금이 int로 변환 유형을 허용합니다

void myFunction(T)(T param) if(is(T:int)) { 
} 
0

D에서 unittest를 사용하는 Functor 법칙과 같은 제약 조건을 정의 할 수 있습니까? 매우 좋을거야.

Phobos는 모노도 및 펑터 및 모나드처럼 언어의 또 다른 개념을 가지고 있습니다. 그리고 그것은 Ranges입니다. 이제 Phobos가 유형이 범위인지 확인하는 방법은 유형에서 특정 함수를 호출 할 수 있는지 확인하는 템플릿을 정의하는 것입니다. 이 함수들이 제네릭 일 경우, 템플릿의 답은 컴파일러가 자신의 타입에 맞는 메소드를 찾을 수 있는지에 달려 있습니다.

refenrence를 들어, here's the typecheck for a ForwardRange (링크 점을 더 문서와 코드) :

template isInputRange(R) 
{ 
    enum bool isInputRange = is(typeof(
    (inout int = 0) 
    { 
     R r = R.init;  // can define a range object 
     if (r.empty) {} // can test for empty 
     r.popFront();  // can invoke popFront() 
     auto h = r.front; // can get the front of the range 
    })); 
} 

을두고 당신과 같이 템플릿 제약 조건을 만들 수 있습니다

template isFunctor(Testant) { 
    enum bool isFunctor = is(typeof(
     () 
     { 
      Testant t = Testant.init;   // can instantiate that type 
      auto result = t.fmap((Testant){}); // can call fmap on it with the type as parameter. 
     } 
} 

주 fmap 함수와 UFCS을 위 fmap이 여전히 당신의 데칼레이션과 일치합니다.

클래스 대신 structs를 사용하는 것이 더 좋습니다. 값 유형이므로 D에서 CTFE (Compilation Time Function Execution)를 사용할 수 있으므로 opCall을 영리하게 사용하여 함수 자체처럼 사용할 수 있습니다.

관련 문제