Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Short-circuit AND within IO Monad

Tags:

haskell

I know the question has been asked there but I can't believe there is no straight answer.

I understand it's not good to hide side-effect inside a (&&) but in my case the side-effect are just checking something in the outstide world (existence of a file, check modification time etc, ask user a yes/no quistion).

So what is the haskell way to something like this, so that cond2 is not executed 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 equivalent, but I can't find anything.

Update

I can see lots of manual solution. I'm still puzzled that this function doesn't exists somewhere. One advantage of lazzy evaluation is it doesn't only short-circuit for hard-coded && like in C. It is really strange that when in imperative mode, Haskell can't even short-circuit &&. Although, all solution use somehow and if to short-circuit the evaluation. Is there not a way to make a generic lazzy liftM2 ?

like image 950
mb14 Avatar asked Nov 23 '14 18:11

mb14


People also ask

What is IO Monad?

So, What is an IO Monad? IO Monad is simply a Monad which: Allows you to safely manipulate effects. Transform the effects into data and further manipulate it before it actually gets evaluated.

Why is IO a Monad in Haskell?

The I/O monad contains primitives which build composite actions, a process similar to joining statements in sequential order using `;' in other languages. Thus the monad serves as the glue which binds together the actions in a program.

Is IO Monad a state Monad?

The IO monad in Haskell is often explained as a state monad where the state is the world.

Is IO a Monad Haskell?

The IO type constructor provides a way to represent actions as Haskell values, so that we can manipulate them with pure functions. In the Prologue chapter, we anticipated some of the key features of this solution. Now that we also know that IO is a monad, we can wrap up the discussion we started there.


2 Answers

This is what Pipes.Prelude.and does, going over a lazy stream of effectfully-generated conditionals and short-circuiting 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:

  • and
  • Pipes tutorial
like image 79
Gabriella Gonzalez Avatar answered Sep 23 '22 23:09

Gabriella Gonzalez


This isn't different from what some others are saying, but isn't it simplest just to 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 didn't 'short-circuit', then the undefined cell would have been evaluated and returned an exception.

It is a little irritating that liftM2 (&&) doesn't work as one hoped.

Edit: I just noticed that, as one might have expected, 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

like image 24
Michael Avatar answered Sep 26 '22 23:09

Michael