是否按照标准Haskell重写GADT代码?

时间:2018-08-12 12:47:59

标签: haskell gadt

我试图理解Heinrich Apfelmus的文章 The Operational Monad Tutorial ,他经常使用GADTs。作为一项智力活动,我尝试重写他的代码示例,以使他们不再使用GADT。我做不到,现在我可以确定这是因为我的技能有限,还是存在根本问题。

r/haskell上,爱德华·克梅特(Edward Kmett)指出:“ 如果您具有Rank N类型,则可以始终通过类将GADT转换为最终的[sic]无标签表示形式。

但是,如果我也不想使用Rank N类型怎么办?我想,我必须牺牲一些东西,但我仍然应该能够做到。

因此,如果我愿意牺牲某种类型的安全性,请使用幻像类型,类型类之类的东西,那么我可以为下面的表达式(有点)编写一个 eval 函数,而无需使用LANGUAGE个扩展名?

                           -- using GADTs :
data Expr = I Int  |       -- Int  -> Expr Int
            B Bool |       -- Bool -> Expr Bool
            Add Expr Expr  -- Expr Int -> Expr Int -> Expr Int
            Eq  Expr Expr  -- Expr 1   -> Expr a   -> Expr Bool

2 个答案:

答案 0 :(得分:7)

没有GADT,您不知道Expr的类型是否正确,因此您只能实现可能引发错误的eval

eval :: Expr -> Maybe (Either Int Bool)
eval (I n) = pure (Left n)
eval (B b) = pure (Right b)
eval (Add e1 e2) = do
  x1 <- eval e1
  x2 <- eval e2
  case (x1, x2) of
    (Left n1, Left n2) -> pure (Left (n1 + n2))
    _                  -> Nothing
eval (Eq e1 e2) = do
  x1 <- eval e1
  x2 <- eval e2
  case (x1, x2) of
    (Left  n1, Left n2)  -> pure (Right (n1 == n2))
    (Right b1, Right b2) -> pure (Right (b1 == b2))
    _                    -> Nothing

答案 1 :(得分:5)

没有GADT,我们需要一个Value和类型,包括所有可能的结果。我们还需要使评估函数部分化或返回类似Maybe Value的内容。

data Value = VI Int | VB Bool

eval :: Expr -> Value
eval (I i) = VI i
eval (B b) = VB b
eval (Add e1 e2) = case (eval e1, eval e2) of
   (VI i1, VI i2) -> VI (i1+i2)
   _              -> error "runtime type error"
...