如果多个monad"混合",是否有可能利用monadic结构?

Ana*_*Ana 3 monads haskell 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
Run Code Online (Sandbox Code Playgroud)

假装的Just 1,Just 2,Just 3是函数调用的返回Maybe Int.

整个函数都在一个内部,ExceptT因为我想抛出异常.但内心实际上只是Maybe被操纵的很多价值观.

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

Ben*_*son 6

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

enrich :: MonadError e m => e -> Maybe a -> m a
enrich e Nothing = throwError e
enrich e (Just x) = return x
Run Code Online (Sandbox Code Playgroud)

我正在使用MonadError- m可以抛出类型错误的monad 类e- 来概括类型enrich.例如,我们可以使用它,如果它有型e -> Maybe a -> Except e a或者e -> Maybe a -> Either e a,因为ExceptEither是的两个实例MonadError.

现在,您只需使用一次enrichMaybe值提升到更丰富的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]
Run Code Online (Sandbox Code Playgroud)

如果您使用的单子可适用地 -也就是说,你不使用先前的结果确定后计算-有概括此功能工作在任意数量的惯用方法Maybe秒.我们将把它推Maybes入一个列表,以及我们需要的额外数据来丰富它 - 在这种情况下,错误消息.然后我们可以traverse(née mapM)列表来丰富每个Maybe内部并将它们加入到更大的monadic动作中.

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)]
Run Code Online (Sandbox Code Playgroud)

将效果视为一流公民的能力就是为什么函数式编程是一件好事.