14

私は把握しようとしGADTsています、そして私はGHCのマニュアルのGADTの例を見てきました。私が知る限り、同じことを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)

evalGHCの例とまったく同じコンストラクターと、(インスタンス定義全体に広がる)のまったく同じコードがあることに注意してくださいGADTs

それで、すべてのファズはGADTs何ですか?できないGADTsことでできることはありMultiParamTypeClassesますか?MultiParamTypeClassesそれとも、代わりに私ができることを行うためのより簡潔な方法を提供するだけですか?

4

2 に答える 2

13

同じタイプでコンストラクターが異なるGADT値をコンテナーに入れると、便利です。

map eval [Lit 1, If (IsZero (Lit 3)) (Lit 4) (Succ (Lit 6))]

は簡単ですが、機能従属性を持つ個別のタイプとMPTCを使用して同じものを取得することは少なくとも困難です。マルチパラメーター型クラスのアプローチではLitIfは異なる型のコンストラクターであるため、同じコンテナーにそれらを配置するにはラッパー型が必要になります。ラッパータイプは、私が見る限り、実存的なタイプである必要があります。

data Wrap t = forall a. (IsTerm a t) => Wrapper a

instance IsTerm (Wrap t) t where
    eval (Wrapper e) = eval e

ある種の安全性とリストのmapように機能する能力を確保するため。evalつまり、利便性を除いて、GADTに戻る途中かそれ以上です。

GADTなしでは達成できないことをGADTで実行できるものがあるかどうかはわかりませんが、いくつかのことで多くの優雅さが犠牲になります。

于 2012-06-12T10:49:39.357 に答える
0

GADTsコンストラクターを定義するより自然な方法を提供し、型レベルでのマッチングとコンストラクターをすべて一緒に使用できるようにします(これなしでは実行できないことだと思います)。

{-# LANGUAGE GADTs #-}
data Term a = (a ~ Bool) => IsZero (Term Int)
            | (a ~ Int) => Lit Int
eval :: Term a -> a
eval (IsZero t) = eval t == 0
eval (Lit a) = a
于 2012-06-12T12:53:45.017 に答える