打破循环

Breaking the loop

我有以下代码示例:

data Smth = A | B

data MyError = MkMyError

data MyState = MkMyState

run :: [Smth] -> Either MyError (Maybe Integer)
run param =
  evalState
    ( foldM
        ( \acc a -> do
            res <- go a
            case res of
              Right (Just _) -> undefined -- I want to break here when Right value is Just
              _ -> return (acc >> res)
        )
        (Right Nothing)
        param
    )
    MkMyState
  where
    go :: Smth -> State MyState (Either MyError (Maybe Integer))
    go = undefined

我有按顺序处理的 Smth 列表,它们根据 State monad 中的状态和 Smth 值处理结果。

我想在 go 结果为 MyError 时插入 runEither 的左值)。 这适用于使用 >> 运算符的代码片段。

但是,我也想有可能在 go 函数结果为 Right (Just _) 时中断折叠(行中有注释)。

问题

当我得到 Just 值时如何打破下面的循环? 我想在两种情况下打破循环:

这是怎么编的?

只要 go 不断返回 Right Nothing 并在第一个 go 调用结果时停止,我是否正确认为您只想处理 SmthLeft _Right (Just _) 中没有 运行ning 任何更多 go 电话?

如果是这样,我认为您的 foldM 在这里没有任何意义。如果出现错误或 Just,您想立即停止,但 foldM 只是在错误或 Just 之后继续处理 Smths。 acc >> res 确保折叠最终 returns 第一个错误的值,但您仍然处理所有 Smths(或 运行 永远,如果输入列表是无限的)。

相反,您需要 process:

run :: [Smth] -> Either MyError (Maybe Integer)
run param = evalState (process param) MkMyState
  where
    process :: [Smth] -> State MyState (Either MyError (Maybe Integer))
    process (a:as) = do
      res <- go a
      case res of
        Right Nothing -> process as
        _ -> return res -- stop on Left _ or Right (Just _)
    process [] = return $ Right Nothing

    go :: Smth -> State MyState (Either MyError (Maybe Integer))
    go = undefined

如果你真的想把 process 写成折叠,你可以,虽然它只是一个 foldr,而不是 foldM:

process :: [Smth] -> State MyState (Either MyError (Maybe Integer))
process = foldr step (return $ Right Nothing)
  where step a acc = do
          res <- go a
          case res of
            Right Nothing -> acc
            _ -> return res