我在操作包中使用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
作为参数进行统一?
答案 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