2012-11-09 9 views

Odpowiedz

18

Odpowiedź zależy od problemu, który próbujesz rozwiązać. F # nie ma typeklasses i GADTs, więc nie ma bezpośredniego mapowania. Jednak F # ma różne mechanizmy, które można wykorzystać do rozwiązywania problemów, które zazwyczaj rozwiązać w Haskell pomocą GADTs i typeclasses:

  • Jeśli chcesz reprezentować struktury obiektu i móc dodawać nowe konkretne implementacje z różnych zachowań, wtedy możesz często używać standardowego OO i interfejsów.

  • Jeśli chcesz napisać rodzajowy kod numeryczny, można użyć ograniczeń członków statycznych (here is an example), który jest prawdopodobnie technicznie najbliższy mechanizm typu zajęcia.

  • Jeśli chcesz napisać bardziej zaawansowany kod ogólny (jak uniwersalna drukarka lub analizator składni), możesz często korzystać z funkcji powerful F# runtime reflection.

  • Jeśli potrzebujesz sparametryzować kod za pomocą zestawu funkcji (wykonujących różne podprogramy wymagane przez kod), możesz przekazać implementację interfejsu jako @pad.

Jest też sposobem emulate Haskell type classes in F#, ale zwykle nie jest idiomatyczne F # rozwiązanie, ponieważ F # programowanie styl różni się od stylu Haskell w wielu aspektach. Jednym z dość standardowych zastosowań jest zdefiniowanie przeciążonych operatorów (patrz: this SO answer).

Na poziomie meta pytanie o to, co jest odpowiednikiem funkcji X w innym języku, często prowadzi do niejasnej dyskusji, ponieważ X może być używane do rozwiązywania problemów A, B, C w jednym języku, podczas gdy inny język może udostępniać różne funkcje w celu rozwiązania tych samych problemów (lub niektóre problemy mogą w ogóle nie istnieć).

8

W języku F # często używa się interfaces i inheritance do tych celów.

Przez wzgląd na przykłady, tutaj jest prosta typeclass użyciu interfejsów i object expressions:

/// Typeclass 
type MathOps<'T> = 
    abstract member Add : 'T -> 'T -> 'T 
    abstract member Mul : 'T -> 'T -> 'T 

/// An instance for int 
let mathInt = 
    { new MathOps<int> with 
     member __.Add x y = x + y 
     member __.Mul x y = x * y } 

/// An instance for float 
let mathFloat = 
    { new MathOps<float> with 
     member __.Add x y = x + y 
     member __.Mul x y = x * y } 

let XtimesYplusZ (ops: MathOps<'T>) x y z = 
    ops.Add (ops.Mul x y) z 

printfn "%d" (XtimesYplusZ mathInt 3 4 1) 
printfn "%f" (XtimesYplusZ mathFloat 3.0 4.0 1.0) 

To nie może wyglądać bardzo piękne, ale to F # -ish sposób to zrobić. Aby uzyskać bardziej podobne do Haskella rozwiązanie, które używa słownika operacji, możesz rzucić okiem na this nice answer.

+1

To jest wprowadzający w błąd przykład, ponieważ dla kodu numerycznego wystarczy napisać: "niech wbudowane XtimesYplusZ x yz = (x * y) + z' i" XtimesYplusZ 3 4 1 "i" XtimesYplusZ 3.0 4.0 1.0 "będą działały. Ale oczywiście w innym scenariuszu kod oparty na stylu, który demonstrujesz, byłby dobrym sposobem na modelowanie tego rodzaju parametryzacji według operacji. Sądzę, że to właśnie mam na myśli mówiąc, że istnieją różne podejścia do różnych problemów rozwiązanych przez klasy typów w Haskell. –

+1

Tak, starałem się znaleźć dobry przykład. To, co chciałbym zademonstrować, to tylko styl kodowania; nie chodzi o kod liczbowy. – pad