91

I want to do something in Haskell that looks like this:

main1 = do s <- getLine
           if s == "foo" then putStr "You entered foo"

Obviously this isn't legal since there's no else. One alternative I've thought of:

nop :: IO ()
nop = sequence_ []

main2 = do s <- getLine
           if s == "foo" then putStr "You entered foo" else nop

This is a little verbose, but I would settle for it if necessary. I would be surprised if there weren't a built-in version of nop, though.

Alternatively:

doIf :: Bool -> IO () -> IO ()
doIf b m = if b then m else nop

main3 = do s <- getLine
           doIf (s == "foo") (putStr "You entered foo")

This is more concise, but the syntax is not particularly nice. Again, I wouldn't be surprised to find something built-in that already exists.

What's the preferred way to do this?

Don Stewart
  • 137,316
  • 36
  • 365
  • 468
Dave B
  • 1,091
  • 2
  • 8
  • 5

2 Answers2

132

The easiest way to do a no-op in a monad is:

return ()

Equivalently:

pure ()

However, for the particular idiom you're doing, there's a combinator already made for you:

import Control.Monad
main = do s <- getLine
          when (s == "foo") $ putStr "You entered foo"

This when combinator behaves exactly like your doIf combinator :)

dfeuer
  • 48,079
  • 5
  • 63
  • 167
bdonlan
  • 224,562
  • 31
  • 268
  • 324
  • 1
    Whoops, I thought about return () but was thinking that it would actually return (i.e. short-circuit the rest of the stuff in the do-expression). My bad. Thanks for the pointer to when. – Dave B May 07 '09 at 04:02
  • 7
    return is kind of a bad name for it, yeah :) – bdonlan May 07 '09 at 04:58
  • 9
    @Dave Keep in mind that `return` in Haskell isn't a language construct, it's just a function (with a badly chosen name, as bdonian says). Return doesn't effect the control flow, or something, you could write: `do {s <- getLine; return (); putStrLn s}` that would execute just fine. – Tom Lokhorst May 07 '09 at 05:36
  • I am getting ``Not in scope: `when'`` for `test = do (when True (putStrLn "Hello"))`. – Qwertie Sep 11 '14 at 23:29
  • 3
    Oops, `when` requires `import Control.Monad` at the top of the file. – Qwertie Sep 18 '14 at 18:58
  • Note that in [*How to declare an imperative*](http://dl.acm.org/citation.cfm?id=262011) (1997), Philip Wadler uses `done` which can be defined as `done = return ()` (page 245). – Alexey Jul 30 '17 at 19:15
23

You can use Hoogle to find functions, in this case: when.

In Hoogle, you can enter the type signature, and it will try to find matching functions in the standard libraries by unifying the types and reordering arguments.

In your case, you can simply enter the type of your doIf function: Bool -> IO () -> IO () . when is the third answer here, its reverse unless is there also.

Tom Lokhorst
  • 13,658
  • 5
  • 55
  • 71