我正在使用Heinrich Apfelmus 的操作单元.我想用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
Run Code Online (Sandbox Code Playgroud)
现在我将最后一行更改为
eval (Display i :>>= is) s = display i >> interp (is ()) s
Run Code Online (Sandbox Code Playgroud)
并且类型推断不再成功,我得到输出
无法从上下文(Monad m)中推导出(m~m1)
由类型签名绑定的解释:: Monad m =>(Int - > m()) - > Elo a - > Int - > ma(... )
当我删除interp的类型签名时,我得到一个额外的错误(无法推断(a1~a)).
当我将所有m更改为IO时(如操作monad的tic tac toe示例),然后再次编译.
我是在尝试一些没有意义的事情,还是可以向GHC提供一些提示?我不得不承认我不确定我是否需要这种灵活性.
那是因为m本地类型签名是新的类型变量,所以他们承诺可以使用任何 Monad.如果使用display,eval只能用于特定的monad display用途.如果你a)删除本地类型签名,或b)将类型变量m放入范围,它应该工作
{-# LANGUAGE ScopedTypeVariables #-}
...
interpret :: forall m. (Int -> m ()) -> Elo a -> Int -> m a
Run Code Online (Sandbox Code Playgroud)