Dax Fohl
Dax Fohl

Reputation: 10781

Is there any way to use IO Bool in if-statement without binding to a name in haskell?

If I've got a function that returns IO Bool (specifically an atomically), is there any way to use the return value directly in the if statement, without binding?

So currently I've got

ok <- atomically $ do
  ...
if (ok) then do
  ...
else do
  ...

Is it at all possible to write this as something like

if (*some_operator_here* atomically $ do
      ...) then do
  ...
else do
  ...

I was hoping there'd be a way to use something like <- anonymously, i.e., if (<- atomically ...) but so far no such luck.

Similarly on getLine, is it possible to write something like

if ((*operator* getLine) == "1234") then do ...

Related addendum--what is the type of (<-)? I can't get it to show up in ghci. I'm assuming it's m a -> a, but then that would mean it could be used outside of a monad to escape that monad, which would be unsafe, right? Is (<-) not a function at all?

Upvotes: 16

Views: 6453

Answers (3)

Joachim Breitner
Joachim Breitner

Reputation: 25763

With GHC 7.6 and the LambdaCase language extension, you can write

{-# LANGUAGE LambdaCase #-}

import System.Directory

main = do
    doesFileExist "/etc/passwd" >>= \case
        True ->  putStrLn "Yes"
        False -> putStrLn "No"

It is not exactly if..then..else, but closer enough, does not require binding to the result, and some people (not me) say that if..then..else is bad style in Haskell anyways.

Upvotes: 8

Satvik
Satvik

Reputation: 11208

You can use ifM from Control.Conditional if that suits your purpose and its not even hard to write a similar function.

Just to give you example

import Control.Conditional
import Control.Monad

(==:) :: ( Eq a,Monad m) => m a -> m a -> m Bool
(==:) = liftM2 (==)

main = ifM (getLine ==: getLine) (print "hit") (print "miss")

I think there are ways using rebindable syntax extension that you can even use if c then e1 else e2 like syntax for ifM but it is not worth the effort to try that.

Upvotes: 17

Daniel Pratt
Daniel Pratt

Reputation: 12077

No, you cannot. Well, to be honest, there is a 'hack' that will allow you to at least write code like this and get it to compile, but the results will almost certainly not be what you wanted or expected.

Why is this not possible? Well, for one thing a value of type IO Bool does not in any sense contain a value of type Bool. Rather it is an 'action' that when performed will return a value of type Bool. For another thing, if this were possible, it would allow you to hide side-effects inside what appears to be pure code. This would violate a core principal of Haskell. And Haskell is very principled.

Upvotes: 1

Related Questions