Note

These slides are also available in PDF format: 4:3 PDF, 16:9 PDF, 16:10 PDF.

## Input and Output¶

### Purely Functional Languages¶

Up until this point, our usage of Haskell has been in a world without side effects, where we need not worry about functions changing the state of the world…

Input and output is dangerous… we’re changing the state of the output device (or file) we are connected to, or the file we are reading might contain state information.

Haskell has a clever system of separating parts of our program which are pure and the parts which are impure…

### IO Tagged Types¶

Haskell only allows IO from types that are “tagged” with IO. We can tag a type with IO by writing IO with a space in front of it:

-- This function is built into Haskell
getChar :: IO Char
-- definition not shown...


When we preform an IO action but return no useful data, we tag the unit type ((), empty parentheses) with IO:

-- This function is built into Haskell
putChar :: Char -> IO ()
-- definition not shown...


### The main Function¶

To run your program, Haskell expects that you write a function called main that preforms IO actions. Let’s use the really simple function putStrLn which writes a line of text to the screen to see how this works:

-- Not my first Haskell program!
main :: IO ()
main = putStrLn "Hello, World!"


### Sequencing Actions¶

Using the do syntax, you can run a series of IO actions in order:

main = do
putStrLn "Hello, World!"
putStrLn "This program runs functions in order!"


Note

do is really just a fancy syntax for chaining together the >>= (“bind”) operator, but usage of that operator is really just silly; I don’t expect you to know or use it.

### print¶

print is equivalent to putStrLn . show, in other words, it converts any object with a string representation to a string, then prints the result. For example:

factorial' :: Int -> Int
factorial' 0 = 1
factorial' n = n * factorial' (n - 1)

main = do
print $factorial' 5 print$ factorial' 10


### The <- Operator¶

Similar to let and where, <- lets you give a variable a value, but is allowed for IO tagged results: the result may not always be the same value.

main = do
name <- getLine
putStrLn $"Nice to meet you, " ++ name ++ "!"  Once the do block ends, the value of name is lost. ### Making Strings Useful Things¶ Data which has the Read type class (for example, integers) can be created from strings using the read function. main = do putStrLn "What number would you like factorialized?" num <- getLine print$ factorial $read num  Why did we not have to specify the type? Haskell is clever, figured out that num must be what factorial takes, an Int. If we wanted to explicitly specify this: main = do putStrLn "What number would you like factorialized?" num <- getLine print$ factorial $(read num) :: Int  ### The return function¶ The return function helps us make fake IO actions, for example, if we wanted to use <- to give values to variables: main = do a <- return "CSCI-400" b <- return "Rocks!" putStrLn$ a ++ " " ++ b


Note that you could just use let or where in this case, but you’ll see good use for return soon…

Note that the return function does not return from a function call.

### Impure map: Introducing mapM¶

mapM takes an IO action, and applies the IO action to a sequence of elements:

GHCi> mapM print (filter odd [1..10])
1
3
5
7
9
[(),(),(),(),()]


Haskell also has mapM_, which discards the result of the mapping if you don’t care about it.

### forM¶

forM could be defined as:

forM = flip mapM


In other words, it’s equivalent to mapM but takes it’s arguments backwards. This leads to some cool use:

weekdays = ["Sun","Mon","Tue","Wed","Thu","Fri"]

main = do
shirts <- forM weekdays (\ w -> do
putStrLn $"What do you wear on " ++ w ++ "?" shirt <- getLine return shirt) mapM_ print shirts  ### Forever¶ forever takes an IO action and repeats that IO action forever. main = forever$ do
printStrLn "Are we there yet?"


Food For Thought

How might we write forever?

### Activity: Interacting with a Function¶

Take any pure function you’ve written for this course, and using forever, repeatedly prompt for input, and print the result of the function.

Share computers as necessary.

### Conditionals in IO¶

Note that our usage of if and else has not changed, we just need to be careful about returning the correct type for IO, and remembering that every if must be paired with an else:

main = do
putStrLn "Do you wear different shirts by weekday?"
response <- getLine
if response == "YES"
then do
shirts <- promptShirts
mapM print shirts
else return ()