I think using &&
for conditional execution is something of a bad habit. Sure it's just a matter of reason to do this for side-effect-free stuff like the False && all (/=0) [1..]
, but when there are side-effects it's quite confusionsome to make them dependent in such a hidden way. (Because the practise is so widespread, most programmers will immediately recognise it; but I don't think it's something we should encourage, at least not in Haskell.)
What you want is a way to express: "execute some actions, until one yields False
".
For your simple example, I'd just do it explicitly:
main = do
e0 <- run "foo"
when e0 $ run "bar"
or short: run "foo" >>= (`when` run "bar")
.
If you want to use this more extensively, it's good to do it in a more general manner. Simply checking a boolean condition is not very general, you'll normally also want to pass on some kind of result. Passing on results is the main reason we use a monad for IO, rather then simply lists of primitive actions.
Aha, monads! Indeed, what you need is the IO monad, but with an extra "kill switch": either you do a sequence of actions, each possibly with some result to pass on, or – if any of them fails – you abort the entire thing. Sounds a lot like Maybe
, right?
http://www.haskell.org/hoogle/?hoogle=MaybeT
import Control.Monad.Trans.Maybe
run :: String -> MaybeT IO ()
run s = MaybeT $ do
e <- system s
return $ if exitCodeToBool e then Just () else Nothing
main = runMaybeT $ do
run "foo"
run "bar"
liftM2
. You need a monadic version of(&&)
that has the (monadic) strictness you want. – Obscenity