【发布时间】:2013-04-29 05:33:03
【问题描述】:
假设我有这两个功能:
errorm :: ( MonadError String m ) => Bool -> m Int
errorm cond = if cond then return 1 else throwError "this is an error"
errorms :: ( MonadError String m ) => Bool -> m String
errorms cond = if cond then return "works" else throwError "does not work"
如你所见,一个在安全的情况下返回一个字符串,而另一个返回一个int
我现在想在另一个 monad 中一起使用它们。琐碎:
errErr :: MonadError String m => Bool -> Bool -> m (Int, String)
errErr b1 b2 = do
a <- errorm b1
b <- errorms b2
return (a,b)
这里的函数签名是由GHC派生的,我不知道如何使用这个函数。我试过这个:
runErrorT ( runErrorT ( errErr1 True True ) ) -- should give me (Right 1, Right "works")
但它给了我:
Ambiguous type variable `e0' in the constraint:
(Error e0) arising from a use of `errErr1'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `runErrorT', namely `(errErr1 True True)'
In the first argument of `runErrorT', namely
`(runErrorT (errErr1 True True))'
In the expression: runErrorT (runErrorT (errErr1 True True))
总的来说,这只是我的问题的一个例子。我觉得我没有掌握如何准确堆叠两个属于同一类但具有不同类型参数的 monadT。另一个例子可能是堆叠一对函数:
f :: ( MonadState Int m ) => m ()
g :: ( MonadState String m ) => m ()
----------------------------------- - - - 更新 - - - - - - - - - - - - - - - - - - - - - - --------
根据 Daniel 在下面的评论,我从上面添加了函数 f 和 g 的具体实例。但多亏了 Tikhon 的回答,我想我明白了。
type Counter = Int
type Msg = String
incr :: (MonadState Counter m) => Counter -> m ()
incr i = modify (+i)
addMsg :: ( MonadState Msg m ) => Msg -> m()
addMsg msg = modify ( ++ msg )
incrMsg:: (MonadTrans t, MonadState Msg m, MonadState Counter (t m)) => t m ()
incrMsg = do
lift . addMsg $ "one"
incr 1
return ()
incrMsgt = runIdentity $ runStateT ( runStateT incrMsg 1 ) "hello" :: (((), Int), String)
【问题讨论】:
-
你只需要一个
runErrorT,errorm和errorms在同一个monad 中愉快地运行:runErrorT ( errErr True True ) :: [Either String (Int,String)]产生[Right (1,"works")]。 -
在你的例子中,两者都有
MonadError String m约束,只有结果类型参数不同。你不需要任何堆叠。在底部提到的一般情况下,您可以这样做,因为状态类型参数不同。你能澄清一下你到底想解决什么问题吗? -
感谢您的澄清,我没有很好地理解这个问题,所以我不小心将两个问题合二为一。
标签: haskell monads monad-transformers