Lecture 23-2
Writing IO Code
We can write our own IO actions:
print_two :: String -> String -> IO ()
Print_two s1 s2 = putStrLn (s1 ++ s2)
> print_two "abc" "def"
abcdef
Note that the return type is IO ().
Combining Multiple IO Calls
The do syntax allows us to combine multiple IO actions.
get_and_print :: IO ()
get_and_print =
do
x <- getLine
y <- getLine
putStrLn (x ++ " " ++ y)
This syntax allows us two write a sequence of statements that will be executed in order.
You could also write this with the following syntax:
get_and_print :: IO ()
get_and_print = do
x <- getLine
y <- getLine
putStrLn (x ++ " " ++ y)
The do Syntax
A do block has the following syntax:
do
v1 <- [IO action]
v2 <- [IO action]
...
vk <- [IO action]
[IO action]
v1throughvkunbox the results of IO actions.- The final IO action is the return value.
The v <- portion can be skipped if you are using an IO action purely for the side effect.
let in do Blocks
let expressions can be used inside do block in order to complete pure computations:
add_one :: IO ()
add_one =
do
n <- getLine
let num = (read n) :: Int
out = show (num + 1)
putStrLn out
In a do block you can type anything out that you would type into the command line of GHCI.
if in do Blocks
guess :: IO ()
guess = do
x <- getLine
if x == "42"
then putStrLn "Correct!"
else putStrLn "You are very wrong."
Both branches of the if mut have the same type.
do Blocks
do blocks let you sequence multiple actions:
- Works with IO actions.
- Will not work in pure functional code.
Functional programs consist of:
- A small amount of IO code.
- A large amount of pure functional node.
Don’t try to write your entire program in IO code.
Putting Values in the IO Box
Sometimes we need to pus a pure value into IO.
- We can use the
returnfunction to do this.
> :t "hello"
"hello" :: [Char]
> :t return "hello"
IO [Char]
example :: IO String
example = do
x <- getLine
return (tail x)
You must use return to get the value out of an impure function.
print_if_short :: String -> IO ()
print_if_short str =
if length str <= 2
then putStrLn str
else return ()
Both sides of the if must have the type IO ():
- So we use
return ()in theelsepart.
return
This function is not the same as in imperative languages return does not stop execution. It just convert pure values to IO values.
Monad
The type of return mentions monads.
> :t return
return :: Monad m => a -> m a
This is because IO is a monad.
- Whenever you see
Monad m =>substituteIOform. - So
return :: a -> IO a
You don’t need to know anything about monads for COMP105.
Exercises
-
doubleEcho :: IO () doubleEcho = do x <- getLine putStrLn x putStrLn x -
firstWord :: IO () firstWord = do string <- getLine if (words string) == [] then putStrLn "" else putStrLn (head . words $ string) -
printEven :: Int -> IO () printEven x = if (even x) then (putStrLn x) else return ()This doesn’t need to be done in a
doblock as it is just one line.