2
votes

I would like to do something different but it would be too long so below is only example:

test x y = if x == "5" then x
           else do putStrLn "bad value"; y

so if x == 5 it should return x, else it should print 'bad value' and return y - how can I do that in haskell ?


edit:

Why this code returns error: "couldn't match expected type bool with actual type IO bool" ?

canTest :: String -> IO Bool
canTest x = if x == "5" then return True
           else do putStrLn "bad value"; return False

test x y = if canTest x then x
           else y
2
Please don't open a new question on the exact same problem. Rather edit your old one our ask something new. If you need such kind of a debug printf, hoogle for trace.fuz

2 Answers

6
votes

You need to make both sides have the same type, namely IO String. For this you need to use return to lift the values into the monad, i.e.

test :: String -> String -> IO String
test x y = if x == "5"
             then return x
             else do putStrLn "bad value"
                     return y

Now return x has the type IO String, and so does the do block in the else branch.

0
votes

Because canTest has side-effects (i.e. does I/O), its return type is IO Bool, which has two implications:

  1. You cannot test its value directly in the if predicate, you must 'run' the action first, then test the extracted value.
  2. Your edited test function must also be in the IO monad, as you cannot escape IO. (Unless very carefully with unsafePerformIO)

    canTest :: String -> IO Bool
    canTest x = if x == "5"
                  then return True
                  else do putStrLn "bad value"; return False
    
    test :: String -> String -> IO String
    test x y = do xCanTest <- canTest x
                  if xCanTest
                    then return x
                    else return y
    

Results in

Prelude> test "5" "12"
"5"
Prelude> test "6" "12"
bad value
"12"