【问题标题】:Operational monad with interpreter in arbitrary monad在任意单子中带有解释器的操作单子
【发布时间】:2011-12-03 23:58:13
【问题描述】:

我正在使用 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

类型推断不再成功,我得到了输出

无法从上下文 (Monad m) 中推断出 (m ~ m1)
受解释的类型签名约束 :: Monad m => (Int -> m ()) -> Elo a -> Int -> m a (...)

当我删除 interp 的类型签名时,我得到一个额外的错误(无法推断 (a1 ~ a))。
当我将所有 m 更改为 IO 时(如操作 monad 的 tic tac toe 示例中),它会再次编译。
我是在尝试一些没有意义的事情,还是可以向 GHC 提供一些提示?我不得不承认我不确定我是否需要这种灵活性。

【问题讨论】:

    标签: haskell monads


    【解决方案1】:

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

    ,它应该可以工作
    {-# LANGUAGE ScopedTypeVariables #-}
    ...
    interpret :: forall m. (Int -> m ()) -> Elo a -> Int -> m a
    

    【讨论】:

    • 我什至没有尝试 a)(尽管我通常不使用本地类型签名)因为示例代码中的以下语句“请注意,由于 ProgramView 是 GADT,因此类型注释eval 是强制性的。”
    猜你喜欢
    • 2017-07-06
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多