I have the following code sample:
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
I have list of Smth that are processed sequentially and they process a result based on state in the State monad and the Smth value.
I want to break in the run when the go results in MyError (left value of the Either).
This works with the code snippet using the >> operator.
However, I want to also have the possibility to break folding when the go function results in Right (Just _) (There is a comment on the line).
Question
How to break the following loop when I get the Just value?
I want to break the loop in 2 cases:
- in case of error -
goresulting inLeftvalue - in case of
Justvalue -goresulting inRight (Just _)value. This is some kind of flipped behaviour of theMaybemonad and the>>operator. I don't want to break onNothing, but onJust.
How could this be composed?
CodePudding user response:
Am I correct that you want to process the Smths only as long as go keeps returning Right Nothing, and stop at the first go call that results in Left _ or Right (Just _) without running any more go calls?
If so, I don't think your foldM makes any sense here. In case of error or Just, you want to stop right away, but the foldM just keeps processing Smths after the error or Just. The acc >> res makes sure that the fold eventually returns the value of the first error, but you still process all the Smths (or run forever, if the input list is infinite).
Instead, you want something like 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
If you really want to write process as a fold, you can, though it's just a foldr, not a 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
