Ich versuche zu verstehen GADTs
, und ich habe die GADTs example in GHC-Handbuch angeschaut. Soweit ich das beurteilen kann, ist es möglich, die gleiche Sache mit MultiParamTypeClasses
zu tun:GADTs vs. MultiParamTypeClasses
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies,
FlexibleInstances, UndecidableInstances #-}
class IsTerm a b | a -> b where
eval :: a -> b
data IntTerm = Lit Int
| Succ IntTerm
data BoolTerm = IsZero IntTerm
data If p a = If p a a
data Pair a b = Pair a b
instance IsTerm IntTerm Int where
eval (Lit i) = i
eval (Succ t) = 1 + eval t
instance IsTerm BoolTerm Bool where
eval (IsZero t) = eval t == 0
instance (IsTerm p Bool, IsTerm a r) => IsTerm (If p a) r where
eval (If b e1 e2) = if eval b then eval e1 else eval e2
instance (IsTerm a c, IsTerm b d) => IsTerm (Pair a b) (c, d) where
eval (Pair e1 e2) = (eval e1, eval e2)
Beachten Sie, dass wir genau die gleichen Konstrukteure und den exakt gleichen Code für eval
(Spread überquert die Instanzdefinitionen) haben, wie in GHC's GADTs
Beispiel.
Also was ist der ganze Fuzz über GADTs
? Gibt es etwas, was ich mit GADTs
tun kann, dass ich nicht mit MultiParamTypeClasses
tun kann? Oder bieten sie nur einen präziseren Weg, Dinge zu tun, die ich mit MultiParamTypeClasses
stattdessen tun könnte?
In Ihrer Probe können Sie 'If (Lit 3) (IntTerm 1) (IntTerm 2)' konstruieren. Erwägen Sie die Verwendung von 'Daten Wenn a = Wenn BoolTerm a a '. – ony
GADTs bieten nichts an, was nicht durch existenzielle Typen und Gleichheit simuliert werden könnte. Aber Ihr spezielles Beispiel ist kein Beispiel dafür. – augustss
GADTs sind zur Definitionszeit geschlossen, was ein sehr großer Unterschied sein kann. –