The following function executes each action from the list until a predicate returns True. I have a feeling that this function can be rewritten using fold and without the do construct but I don't know how.

execUntil :: (Eq a, Monad m) => [m a] -> (a -> Bool) -> m ()
execUntil [] p = return ()
execUntil (a:as) p = do
    r <- a
    if p r then return () else execUntil as p
  • 1
    \$\begingroup\$ Not sure if this is a question that fits more into stackoverflow. Your code works.. but you're asking how to do a specific thing. \$\endgroup\$
    – lukstru
    Jul 19, 2022 at 18:21
  • \$\begingroup\$ I'm kind of asking for advice on how to improve my code that works. Isn't a code review about it? \$\endgroup\$ Jul 19, 2022 at 18:57
  • \$\begingroup\$ That's why I'm not sure \$\endgroup\$
    – lukstru
    Jul 19, 2022 at 19:08
  • \$\begingroup\$ Since foldM is a left fold, I don't think you can use it for this. You also can't use a non-monadic fold. execUntil is called whileM in Control.Monad.Extra and Control.Monad.Loops, implemented with when rather than if/then/else but otherwise the same. It will still do recursion under the hood but there's no way around this. \$\endgroup\$ Jul 19, 2022 at 19:28

1 Answer 1


Not totally sure what you're looking for, but maybe something like this?

import Control.Monad (void)
import Data.Bool (bool)

execUntil :: Monad m => [m a] -> (a -> Bool) -> m ()
execUntil = flip $ \p -> void . foldl (\ma mb -> ma >>= bool (p <$> mb) (pure True)) (pure False)

I wouldn't recommend it, though. foldl doesn't have any way to short-circuit, so this implementation will traverse the entire [m a], even beyond when the a -> Bool predicate is satisfied.

IMO, the code you've provided is totally fine as-is! Except perhaps for the unnecessary Eq a constraint ;p


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.