如果多个monad是"混合"?

时间:2016-02-18 23:00:27

标签: haskell monads monad-transformers

请考虑以下代码:

run = runExcept $ do
  case Just 1 of
    Nothing -> throwE "escape 1"
    Just x -> do
      case Just 2 of
        Nothing -> throwE "escape 2"
        Just y -> do
          case Just 3 of
            Nothing -> throwE "escape 3"
            Just z -> return z

假设Just 1Just 2Just 3是返回Maybe Int的函数调用。

整个函数在ExceptT内,因为我想抛出异常。但内部真的只是被操纵的Maybe个值。

那么,我是否有可能利用Maybe monad的行为来避免阶梯套管,同时还能抛出异常?

1 个答案:

答案 0 :(得分:6)

您似乎希望使用与哪些失败相关的信息来丰富一系列Maybe操作(如果有的话)。为什么不将丰富实现为一个简单的函数?

enrich :: MonadError e m => e -> Maybe a -> m a
enrich e Nothing = throwError e
enrich e (Just x) = return x

我正在使用MonadError - monads m类,它可以抛出e类型的错误 - 来概括enrich的类型。例如,我们可以像使用e -> Maybe a -> Except e ae -> Maybe a -> Either e a一样使用它,因为ExceptEither都是MonadError的实例。

现在,您只需使用enrich一次将Maybe值提升到更丰富的monadic上下文中。

action = do
    x <- enrich "escape 1" maybe1  -- look mum, no staircasing!
    y <- enrich "escape 2" maybe2
    z <- enrich "escape 3" maybe3
    return [x, y, z]

如果你正在使用你的monad 应用 - 也就是说,你没有使用早期的结果来确定以后的计算 - 有一种惯用的方法来推广这个函数来处理任意数量的{ {1}}秒。我们将把Maybe推入列表,以及我们需要的额外数据来丰富它 - 在这种情况下,错误消息。然后我们可以traverse(néemapM)列表来丰富其中的每个Maybes并将它们加入到更大的monadic动作中。

Maybe

将效果视为一流公民的能力就是为什么功能性编程是一件好事。