操作monad与任意monad的翻译

Dus*_*ang 5 monads haskell

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

Dan*_*her 8

那是因为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)