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 -
go
resulting inLeft
value - in case of
Just
value -go
resulting inRight (Just _)
value. This is some kind of flipped behaviour of theMaybe
monad 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 Smth
s 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 Smth
s 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 Smth
s (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