haskell - 如果多个 monad 为 "mixed",是否可以利用 Monadic 结构?

标签 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 的行为来避免楼梯外壳,同时仍然能够抛出异常?

最佳答案

您似乎想用与哪个失败(如果有)相关的信息来丰富一系列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 值一次提升到更丰富的一元上下文中即可。

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) - 也就是说,您没有使用早期的结果来确定以后的计算 - 有一种惯用的方法可以将此函数推广到任意数量的 也许。我们将把Maybes 以及我们需要丰富它的额外数据放入一个列表中 - 在本例中是错误消息。那么我们就可以traverse (née mapM )列表来丰富其中的每个也许并将它们连接成一个更大的单子(monad) Action 。

enrichMaybes :: (Traversable t, MonadError e m) => t (e, Maybe a) -> m (t a)
enrichMaybes = traverse (uncurry enrich)

action = enrichMaybes [("escape 1", maybe1), ("escape 2", maybe2), ("escape 3", maybe3)]

能够像这样将效果视为一等公民,这就是为什么函数式编程是一件好事。

关于haskell - 如果多个 monad 为 "mixed",是否可以利用 Monadic 结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35494202/

相关文章:

haskell - 存在类型和单子(monad)更改器(mutator)

haskell - 使 Vector.Generic 成为 Functor(和其他类型类

haskell - 将 Haskell 代码移植到新版本的 Data.Map.lookup

scala - 警告 :(55, 56) MoldPiece[PressureData(Int, Prettyprint.YesNo)] 上尚不存在 `withFilter' 方法,请改用 `filter' 方法

asynchronous - 结合 F# 异步和计算表达式

haskell - 在 monad 转换器中使用类型同义词

haskell - 重复追加到字符串haskell

list - Haskell 从文件列表中读取矩阵并使用它

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

scala - 为了理解 future 和两者