haskell - 一些涉及包含 Maybe 的容器的 monad 包装/展开/绑定(bind)困惑

标签 haskell monads monad-transformers

这是一些示例代码

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。

  • foogetStuffSometimes 应该接受 a 类型的内容并返回 Maybe a > 包裹在上下文中 - 也就是说,它们要么返回 Identity (Just a) (计算成功),要么返回 Identity Nothing (计算失败)。

  • getStuffAlways 是一种永不失败的计算 - 它始终返回 Identity a

  • 我希望 foo 能够:

    1. 运行可能失败的计算
    2. 如果可失败计算失败,则失败(无任何结果)
    3. 如果失败的计算成功,则将其与 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/

相关文章:

haskell - Haskell,没有(适用M)的实例

Haskell:模式匹配绑定(bind)运算符时出现刚性类型变量错误

haskell - 实例电感作为约束

haskell - 如何使用比 Stackage Resolver 可用的更新版本的库

haskell - Kleisli 组合并折叠无限列表

列表 Monad : Consequences of the signature of List. flatMap(f: (A) ⇒ GenTraversableOnce[B])

list - 为什么我的代码使用 List 包中的一元列表这么慢?

haskell - MaybeT m 的应用实例假设 Monad m

haskell - 用镜头索引遍历

haskell - 为什么 ICMP 校验和移位 16 位