Я пытаюсь понять GADTs
, и я просмотрел пример GADT в руководстве GHC. Насколько я могу судить, то же самое можно сделать и с 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)
Обратите внимание, что у нас есть те же конструкторы и тот же код для eval
(распространение по определениям экземпляров), что и в примере GADTs
GHC.
Так в чем же вся суета о GADTs
? Что я могу сделать с GADTs
, чего не могу с MultiParamTypeClasses
? Или они просто предоставляют более сжатый способ делать то, что я мог бы делать с MultiParamTypeClasses
вместо этого?
If (Lit 3) (IntTerm 1) (IntTerm 2)
. Рассмотрите возможность использованияdata If a = If BoolTerm a a
. - person ony   schedule 12.06.2012