I am trying following code with try-catch block:
import System.Environment
import System.IO
import System.IO.Error
import Control.Exception
isBinary :: String -> Bool
isBinary ss = do
print "In isBinary fn" -- works if this line is removed.
let ans = any (\c -> ord c > 127) ss
ans
toTry :: String -> IO ()
toTry firline = do
print "In toTry fn."
let answer = isBinary firline
if not answer then do
print "Sent line not binary: "
else
print "Sent line binary"
handler :: IOError -> IO ()
handler e = putStrLn "Whoops, had some trouble!"
ss = "this is a test"
main = do
toTry ss `catch` handler
However, I am getting following error:
$ runghc trycatch3.hs
trycatch3.hs:9:9: error:
• Couldn't match expected type ‘Bool’ with actual type ‘IO Bool’
• In a stmt of a 'do' block: print "in isBinary fn"
In the expression:
do { print "in isBinary fn";
let ans = any (\ c -> ...) ss;
return ans }
In an equation for ‘isBinary’:
isBinary ss
= do { print "in isBinary fn";
let ans = ...;
return ans }
trycatch3.hs:10:30: error:
• Variable not in scope: ord :: Char -> Integer
• Perhaps you meant one of these:
‘or’ (imported from Prelude), ‘odd’ (imported from Prelude)
The error goes away and program works well if the print statement is removed from isBinary function.
Why can't I put print statement in this function?
The answer is, "because types". Specifically:
isBinary :: String -> Bool
isBinary ss = do
....
Since it's a do
block, the return type of isBinary
must match a monadic type Monad m => m t
for some m
and some t
. Here, since print "" :: IO ()
, m
is IO
, so it should've been
isBinary :: String -> IO Bool
isBinary ss = do
and now
print "In isBinary fn" -- works
let ans = any (\c -> ord c > 127) ss -- also works
ans -- doesn't work
ans
doesn't work because of types, again. Its type is Bool
, but it must be IO Bool
-- first, because this do
block belongs to IO
monad, on account of print
; and second, because of the return type of the function as a whole.
Instead, use
return ans
and now it'll work, because return
injects a value into the monadic context, and being the last do
block value it becomes the value produced by the do
block overall (if return val
appears in the middle it just passes the val
to the next step in the combined computation).
The function toTry
will have to be augmented to use the new definition:
toTry :: String -> IO ()
toTry firline = do
print "In toTry fn."
-- let answer = isBinary firline -- incorrect, now!
answer <- isBinary firline -- isBinary ... :: IO Bool
if not answer then do -- answer :: Bool
print "Sent line not binary: "
else
print "Sent line binary"
m a
on the right of <-
, a
on the left.
See this for a general description of do
notation.