GADT在Haskell中打破了等式推理吗?

时间:2016-04-25 16:20:58

标签: haskell gadt

我在操作包中使用ProgramT有以下解释器

{-# LANGUAGE GADTs #-}
import Control.Monad ((<=<))
import Control.Monad.Operational

data Motor' a where
  --Define GADT

serialNewportT :: (Monad m, MonadIO m) => ProgramT Motor' m a -> m a
serialNewportT = eval <=< viewT
  where
    eval :: (Monad m, MonadIO m) => ProgramViewT Motor' m v -> m v
    eval (Return x) = return x
    eval (x :>>= k) = f x >>= serialNewportT  . k

f :: (Monad m, MonadIO m) => Motor' a -> m a
f = undefined -- excluded for brevity

代码,目前的类型检查就好了。但是,我希望能够解决解释器如何处理不同的电机,所以我想让f成为一个参数,而不是硬编码。我已经尝试用这个开关以下代码

{-# LANGUAGE GADTs #-}
import Control.Monad ((<=<))
import Control.Monad.Operational

data Motor' a where
  --Define GADT

serialNewportT :: (Monad m, MonadIO m) => (Motor' a -> m a) -> ProgramT Motor' m a -> m a
serialNewportT f = eval <=< viewT
  where
    eval :: (Monad m, MonadIO m) => ProgramViewT Motor' m v -> m v
    eval (Return x) = return x
    eval (x :>>= k) = f x >>= serialNewportT f . k

但是,此代码失败并显示错误消息

Couldn't match type ‘b’ with ‘c’
   ‘b’ is a rigid type variable bound by
       a pattern with constructor
         :>>= :: forall (instr :: * -> *) (m :: * -> *) a b.
                 instr b -> (b -> ProgramT instr m a) -> ProgramViewT instr m a,
       in an equation for ‘eval’
   ‘c’ is a rigid type variable bound by
       the type signature for
         serialNewportT :: (Monad m, MonadIO m) =>
                           (Motor' c -> m c) -> ProgramT Motor' m a -> m a
 Expected type: Motor' c
   Actual type: Motor' b

由于我只是用同一类型的本地名称替换全局名称,我本以为它应该没有任何障碍。如何将类型与f作为参数进行统一?

1 个答案:

答案 0 :(得分:2)

您没有正确翻译f的类型。在原始代码中,f的类型为forall a . (..) => Motor' a -> m a。它可以使用任何 Motor' a的类型a进行实例化,但在非工作代码中,您声明它的类型与a完全相同ProgramT Motor' m a,而在功能正文中,您在f上为其他(存在量化)类型Motor' b调用b

您只需要更高级别的类型:

serialNewportT :: (Monad m, MonadIO m) => (forall x . Motor' x -> m x) -> ProgramT Motor' m a -> m a