这是一些示例代码
foo :: a -> Identity (Maybe a)
foo a = do
maybeStuff <- getStuffSometimes a
return $ case maybeStuff of -- this "case" stuff is the kind
Just stuff -> Just $ getStuffAlways stuff -- of code I'd expect the Maybe
Nothing -> Nothing -- monad to help with
getStuffSometimes :: a -> Identity (Maybe a)
getStuffSometimes a = return $ Just a
getStuffAlways :: a -> Identity a
getStuffAlways = return
-- ERROR (on the return statement of the do block)
-- Expected type: Identity (Maybe a)
-- Actual type: Identity (Maybe (Identity a))
可能有点不清楚我想要做什么,所以这里有更详细的描述:
所有有趣的东西都包含在计算上下文/容器中 - 在本例中,为了演示,使用了
Identity
。当然,在我的实际代码中我还有另一个 monad。foo
和getStuffSometimes
应该接受a
类型的内容并返回Maybe a
> 包裹在上下文中 - 也就是说,它们要么返回Identity (Just a)
(计算成功),要么返回Identity Nothing
(计算失败)。getStuffAlways
是一种永不失败的计算 - 它始终返回Identity a
。我希望
foo
能够:- 运行可能失败的计算
- 如果可失败计算失败,则失败(无任何结果)
- 如果失败的计算成功,则将其与 getStuffAlways 绑定(bind),并返回
Just(getStuffAlways 的结果为 #1 的结果)
这是 Monad Transformers 的用例吗?就我而言,我的实际 monad 有点复杂,是我的库在 IO 之上提供的多个变压器的堆栈,我不完全确定如何使其适用于这种情况(我会在另一个问题中问它)最终我必须使用变压器)
跟进:
在现实生活中,我有更多类似的东西:
foo :: a -> Identity (a, Maybe a)
foo a = do
firstPart <- getStuffAlways a
maybeStuff <- getStuffSometimes a
secondPart <- case maybeStuff of
Just stuff -> Just $ getStuffAlways stuff
Nothing -> Nothing
return (firstPart, secondPart)
在这种情况下构建堆栈的最佳方法是什么?
最佳答案
是的,这是 monad 转换器的一个用例。给定类型的计算:
computation :: (Monad m) => m (Maybe a)
...您可以使用同名的 MaybeT
构造函数将其包装在 MaybeT
中:
MaybeT :: (Monad m) => m (Maybe a) -> MaybeT m a
MaybeT computation :: (Monad m) => MaybeT m a
然后你可以写:
foo :: MaybeT Identity a
foo = do
stuff <- MaybeT getStuffSometimes
lift $ getStuffAlways stuff
...和 MaybeT
将为您处理所有 Nothing
检查,确保将它们通过您的其他 monad 进行线程化。
完成后,只需使用 runMaybeT
来解开结果,在基本 monad 中返回一个返回 Maybe
的操作:
runMaybeT :: (Monad m) => MaybeT m a -> m (Maybe a)
例如:
runMaybeT foo :: Identity (Maybe a)
编辑:要回答您的后续问题,您只需执行以下操作:
foo a = do
firstPart <- getStuffAlways
secondPart <- runMaybeT $ do
stuff <- MaybeT getStuffSometimes a
lift $ getStuffAlways stuff
return (firstPart, secondPart)
关于haskell - 一些涉及包含 Maybe 的容器的 monad 包装/展开/绑定(bind)困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18026492/