操作monad与任意monad的翻译

时间:2011-12-03 23:58:13

标签: haskell monads

我正在使用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提供一些提示?我不得不承认我不确定我是否需要这种灵活性。

1 个答案:

答案 0 :(得分:8)

这是因为本地类型签名中的m是新类型变量,因此它们承诺使用任何 Monad。如果您使用displayeval只能用于特定的monad display用途。它应该工作,如果你a)删除本地类型签名,或b)将类型变量m带入范围

{-# LANGUAGE ScopedTypeVariables #-}
...
interpret :: forall m. (Int -> m ()) -> Elo a -> Int -> m a