我正在使用Heinrich Apfelmus的operational monad。 我想用monad为结果类型参数化解释器。 我的代码的以下版本编译:
{-# LANGUAGE GADTs #-}
import Control.Monad.Operational
data EloI a where
Display :: Int -> EloI ()
type Elo a = Program EloI a
interpret :: Monad m => (Int -> m ())
-> Elo a
-> Int
-> m a
interpret display = interp
where
interp :: Monad m => Elo a -> Int -> m a
interp = eval . view
eval :: Monad m => ProgramView EloI a -> Int -> m a
eval (Display i :>>= is) s = interp (is ()) s
现在我将最后一行更改为
eval (Display i :>>= is) s = display i >> interp (is ()) s
并且类型推断不再成功,我得到输出
无法从上下文中推导出(m~m1)(Monad m)
由解释的类型签名绑定:: Monad m => (Int - > m()) - > Elo a - > Int - >嘛
(...)
当我删除interp的类型签名时,我收到一个额外的错误(无法推断(a1~a))。
当我将所有m更改为IO时(如操作monad的tic tac toe示例),然后再次编译。
我是在尝试一些没有意义的事情,还是可以向GHC提供一些提示?我不得不承认我不确定我是否需要这种灵活性。
答案 0 :(得分:8)
这是因为本地类型签名中的m
是新类型变量,因此它们承诺使用任何 Monad。如果您使用display
,eval
只能用于特定的monad display
用途。它应该工作,如果你a)删除本地类型签名,或b)将类型变量m
带入范围
{-# LANGUAGE ScopedTypeVariables #-}
...
interpret :: forall m. (Int -> m ()) -> Elo a -> Int -> m a