Short circuit and inside IO Monad

I know that a question was asked there , but I cannot believe that there is no direct answer.

I understand that it is not good to hide the side effect inside (& &), but in my case the side effect just checks something in the outside world (file presence, time to modify the check, etc., ask the user yes / no quistion).

So what is the haskell way for something like this, so cond2 fails if cond1 is false.

cond1, cond2 :: IO bool main = do cond <- liftM2 (&&) con1 con2 if cond then result1 else result2 

I was expecting something like cond <- all [con1, con2] or the equivalent, but can't find anything.

Update

I see a lot of manual solutions. I am still puzzled that this feature does not exist. One of the advantages of lazy evaluations is not only the short circuit for hardcoded && , as in C. It is very strange that when in imperative mode, Haskell cannot even short-circuit && . Although, all solutions are used somehow and, if short-circuited, are estimates. Is there no way to make a general lazy liftM2 ?

+6
source share
5 answers

This is not different from what some others say, but is it not easier to simply emulate the definition of and :

  andM = foldr (&&&) (return True) where ma &&& mb = ma >>= \p -> if p then mb else return p 

then we get, say:

  > let test1 = putStrLn "This test succeeds" >> return True > let test2 = putStrLn "This test fails" >> return False > andM [test1,test2,undefined,undefined] This test succeeds This test fails False 

If andM did not “short-circuit”, then an undefined cell would be evaluated and an exception thrown.

A little annoying that liftM2 (&&) not working, as you might hope.

Edit: I noticed that, as one would expect, this is defined in the monad-loops package http://hackage.haskell.org/package/monad-loops-0.4.2.1/docs/src/Control-Monad-Loops.html #andM

+4
source

This is what Pipes.Prelude.and does by going through a lazy stream of efficiently generated conditional expressions and short circuits if any of them are False :

 import Pipes (each) import qualified Pipes.Prelude as Pipes conds :: [IO Bool] conds = ... main = do cond <- Pipes.and (each conds >-> Pipes.sequence) print cond 

Relevant links:

+8
source

The operation you want is easy to define explicitly.

 shortCircuitAnd :: Monad m => m Bool -> m Bool -> m Bool shortCircuitAnd xy = do r1 <- x -- perform effect of x if r1 then y -- perform effect of y and return result else return False -- do *not* evaluate or perform effect of y 

Of course, you can also use this infix function using backticks:

 x `shortCircuitAnd` y == shortCircuitAnd xy 
+3
source

We can use a monad transformer of type MaybeT , which is an instance of MonadPlus . The idea is to use guard to convert False results to mzero , which will stop the calculation. And then we convert the resulting Maybe result back to Bool .

 import Control.Monad.Trans import Control.Monad.Trans.Maybe effyand :: (Functor m, Monad m) => [m Bool] -> m Bool effyand = fmap isJust . runMaybeT . mapM_ (lift >=> guard) 
+3
source

I would define a monoid like

 newtype AllM m = AllM { getAllM :: m Bool } instance (Monad m) => Monoid (AllM m) where mempty = AllM (return True) mappend (AllM u) (AllM v) = AllM $ u >>= \x -> if x then v else return False 

and then getAllM . mconcat . map AllM $ [con1, con2] getAllM . mconcat . map AllM $ [con1, con2] getAllM . mconcat . map AllM $ [con1, con2] .

+3
source

Source: https://habr.com/ru/post/978584/


All Articles