10 input output handout

Input and Output
Thumrongsak Kosiyatrakul

Thumrongsak Kosiyatrakul
Input and Output

Input and Output
So far, we still cannot receive input from keyboard or print output on the console screen
We will cover the following basics:
What are I/O actions?
How do I/O actions enable us to do I/O? When are I/O actions actually performed?
Unfortunately, I/O actions create an issue that conflicts with how Haskell works?
They are not pure because they have side effects
Input and Output
Thumrongsak Kosiyatrakul

Separating the Pure from the Impure
In Haskell, a function is not allowed to have side effect
If a function is called two times with the same arguments, it must
return the same result
A function cannot change or update variables
When we map a list, we get a new list
ghci> original = [1,2,3] ghci> new = map (*2) original ghci> original
When we insert a new item into our binary search tree, it must return a new tree with new item inserted
If these expressions are in a file, it will cause an error:
myPi = 3.14
myPi = 3.1415
Unfortunately, the output device such as the console screen is also considered to have a state
To display something, simply change the state of the screen
Input and Output
Thumrongsak Kosiyatrakul

Separating the Pure from the Impure
This prevent a Haskell function to display output on the console screen
Note that the output from GHCi is just a test platform
We are talking about running the program from the console
screen without running GHCi
Here is an example of the hello_world.hs:
main = putStrLn “Hello World!!!”
To compile, we use the command ghc with –make option:
$ ghc –make hello_world.hs
[1 of 1] Compiling Main ( hello_world.hs, hello_world.o )
Linking hello_world …
Now, we can execute it just like a regular executable file:
$ ./hello_world
Hello World!!!
Input and Output
Thumrongsak Kosiyatrakul

Separating the Pure from the Impure
Let¡¯s check the putStrLn function in GHCi:
ghci> :t putStrLn
putStrLn :: String -> IO ()
ghci> :t putStrLn “Hello World!!!” putStrLn “Hello World!!!” :: IO ()
The putStrLn takes an argument of type String and returns an I/O action that has a result of type ()
() is known as unit
An I/O action is something that, when performed, will carry out
an action with side effect, and will also present some result Since printing a string to the console does not really have any
kind of return value, so a dummy value of () is used
An I/O action will perform when we give it a name of main and then run the program
Input and Output
Thumrongsak Kosiyatrakul

Gluing I/O Actions
In Haskell, you can only bind a name to an expression
A sequence of I/O actions must be glued into one to be able to
bind with main Here is an example:
putStrLn “What is your name?”
name <- getLine putStrLn ("Hello " ++ name) The do keyword, takes multiple I/O actions and glues them into one I/O action Using the do keyword, the type of its I/O action will be the same as the type of the last I/O action In the above example, the type of main is IO () Input and Output Thumrongsak Kosiyatrakul 浙大学霸代写 加微信 cstutorcs Separating the Pure from the Impure Let¡¯s take a look at the type of getLine ghci> :t getLine
getLine :: IO String
It indicates that getLine is an I/O action that returns a String Note that instead of
name = getLine
name <- getLine This a how Haskell separates pure from impure Since we perform "Hello" ++ name, name must have type But getLine has type IO String To get the result out of an I/O action, we have to use <- If we want to deal with impure data, we must do it in an impure environment Input and Output Thumrongsak Kosiyatrakul Separating the Pure from the Impure Every I/O action yields a result foo <- putStrLn "What is your name?" name <- getLine putStrLn ("Hello " ++ name) RecallthatputStrLnhastypeString -> IO () foo will have type () (kind of useless)
Note that in a do block, the last action cannot be bound to a name
Again about I/O actions:
I/O action will be performed when they are given a name of main or they are inside a bigger I/O action that we composed with a do block
We can use a do block to glue a few I/O actions and then use it inside another do block
The type of a do block is the type of the last I/O action Input and Output
Thumrongsak Kosiyatrakul

Separating the Pure from the Impure
To bind pure values to names, we use the let syntax We can use the let syntax inside I/O action
import Data.Char
putStrLn “What is your name?” name <- getLine let bigName = map toUpper name putStrLn ("Hello " ++ bigName) Again only use <- to bind the result of an I/O action to a name getLine has type IO String With name <- getLine, name will have type String Ifwewritename = getLine,nameisanothernameofthe getLine function Input and Output Thumrongsak Kosiyatrakul Caesar Cipher Program Here is a new version of our Caesar cipher: import System.IO import Data.Char putStrLn "Welcome to Caesar Cipher Program" putStrLn "================================" choice <- prompt "Enter 1 to Encode or 2 to Decode: " key <- prompt "Enter a key (integer): " msg <- prompt "Enter a message: " let result = cipher choice key msg putStrLn ("Result: " ++ result) prompt :: String -> IO String
prompt str = do
putStr str
hFlush stdout
cipher choice key msg = if (read choice :: Int) == 1
then encode (read key :: Int) msg
else decode (read key :: Int) msg
encode :: Int -> [Char] -> [Char]
encode n xs = map (chr . (+n) . ord) xs
decode :: Int -> [Char] -> [Char]
decode n xs = encode (negate n) xs
Input and Output
Thumrongsak Kosiyatrakul

Caesar Cipher Program
The following are encode and decode functions that we discused a while back:
encode :: Int -> [Char] -> [Char]
encode n xs = map (chr . (+n) . ord) xs
decode :: Int -> [Char] -> [Char]
decode n xs = encode (negate n) xs
Consider this cipher function:
cipher choice key msg = if (read choice :: Int) == 1
then encode (read key :: Int) msg
else decode (read key :: Int) msg
Since the type of choice and key are String, we use the read function to turn them into Int
We can also use string comparison for choice
cipher choice key msg = if choice == “1”
then encode (read key :: Int) msg
else decode (read key :: Int) msg
Input and Output
Thumrongsak Kosiyatrakul

Caesar Cipher Program
Let¡¯s take a look at the prompt funciton:
prompt :: String -> IO String
prompt str = do
putStr str
hFlush stdout
This is an I/O action
Inside are I/O actions under a do block
The type of prompt function given a String is IO String which is the type of the getLine function
With the prompt function, we can do this: name <- prompt "Enter your name: " By default, stdout is bufferred until newline is found Toprintanoutputwithoutnewline,hFlush stdoutisusedto flush the stdout To use hFlush, we need to import System.IO Input and Output Thumrongsak Kosiyatrakul Caesar Cipher Program Here is the program again: import System.IO import Data.Char putStrLn "Welcome to Caesar Cipher Program" putStrLn "================================" choice <- prompt "Enter 1 to Encode or 2 to Decode: " key <- prompt "Enter a key (integer): " msg <- prompt "Enter a message: " let result = cipher choice key msg putStrLn ("Result: " ++ result) prompt :: String -> IO String
prompt str = do
putStr str
hFlush stdout
cipher choice key msg = if (read choice :: Int) == 1
then encode (read key :: Int) msg
else decode (read key :: Int) msg
encode :: Int -> [Char] -> [Char]
encode n xs = map (chr . (+n) . ord) xs
decode :: Int -> [Char] -> [Char]
decode n xs = encode (negate n) xs
Input and Output
Thumrongsak Kosiyatrakul

Caesar Cipher Program
To compile:
$ ghc –make caesar.hs
[1 of 1] Compiling Main
Linking caesar …
Here is a couple runs:
$ ./caesar
Welcome to Caesar Cipher Program
================================
Enter 1 to Encode or 2 to Decode: 1
Enter a key (integer): 5
Enter a message: Hello from Haskell
Result: Mjqqt%kwtr%Mfxpjqq
$ ./caesar
Welcome to Caesar Cipher Program
================================
Enter 1 to Encode or 2 to Decode: 2
Enter a key (integer): 5
Enter a message: Mjqqt%kwtr%Mfxpjqq
Result: Hello from Haskell
( caesar.hs, caesar.o )
Input and Output
Thumrongsak Kosiyatrakul

Go back to main is fine:
putStrLn “What is your name? (0 – to exit)”
name <- getLine if name == "0" then return () putStrLn ("Hello " ++ name) main is just another I/O action then and else must have the same type The type of else is IO () We need return () for then return () does not cause the program to terminate return x packs the value x into IO a where a is the type of x msg <- return "Hello" will make the msg to have the value "Hello" of type [Char] Input and Output Thumrongsak Kosiyatrakul Enter a choice without checking: putStrLn "1 - This, 2 - That, 3 - Exit" choice <- getLine if choice /= "3" then doWork choice else return () doWork choice = if choice == "1" then putStrLn "This" else putStrLn "That" If a user enter something other than 1, 2, or 3, it will print That Input and Output Thumrongsak Kosiyatrakul Ask until a valid choice is enter: choice <- getOneTwoOrThree if choice == "3" then return () else doWork choice getOneTwoOrThree = do putStrLn "1 - This, 2 - That, 3 - Exit" tempChoice <- getLine if tempChoice == "1" || tempChoice == "2" || tempChoice == "3" then return tempChoice putStrLn "Invalid input..." getOneTwoOrThree doWork choice = if choice == "1" then putStrLn "This" else putStrLn "That" Input and Output Thumrongsak Kosiyatrakul The putStr Function putStr takes a string as an argument and returns an I/O action that will print that string to the terminal Example putStr "Hello " putStr "World" putStr "!!!" Hello World!!! Note that putStr does not jump into a new line after printing If you want to see the output without printing a newline, use hFlush stdout Input and Output Thumrongsak Kosiyatrakul The putChar Function putChar takes a character and returns an I/O action that will print it to the terminal Example: putChar 'D' putChar 'o' putChar 'g' putStr can be defined using putChar as shown below: putStr :: String -> IO ()
putStr [] = return ()
putStr (x:xs) = do
Input and Output
Thumrongsak Kosiyatrakul

The print Function
print takes a value of any type that is an instance of the Show type class and output the value on the terminal followed by a newline
Basically,
print x = putStrLn (show x)
print True
print [1,2,3]
print “Hello”
print 3.14159265
3.14159265
Every time we type a value in GHCi, it actually call the print function on that value
Input and Output
Thumrongsak Kosiyatrakul
程序代写 CS代考 加QQ: 749389476
The when Function
when is a function that behaves like the if statement To use when, we need to import Control.Monad when takes a Bool and an I/O action
If the Bool is true, it returns the I/O action Otherwise, it return return () action
input <- getLine when (input == "Hello") (putStrLn "What's Up???") Without when: input <- getLine if (input == "Hello") then putStrLn "What's Up???" else return () Input and Output Thumrongsak Kosiyatrakul The sequence Function The sequence function takes a list of I/O actions and returns an I/O action that will perform those actions one after another The following program will wait for a user to enter three lines: lst <- sequence [getLine, getLine, getLine] You may see something strange when the sequence function is used in GHCi: ghci> sequence (map print [1,2]) 1
sequence returns the list of actions and GHCi prints it
Input and Output
Thumrongsak Kosiyatrakul
Programming Help
The mapM Function
Mapping a function that returns an I/O action over a list is quite common
Instead of using sequence and map, the utility functions mapM and mapM_ is provided
mapM takes a function and a list, maps the function over the list, and then sequence it
mapM_ does the same thing, but it throws away the result later Example:
ghci> mapM print [1,2,3] 1
[(),(),()]
ghci> sequence [print 1, print 2, print 3] 1
[(),(),()]
ghci> mapM_ print [1,2,3]
Input and Output
Thumrongsak Kosiyatrakul

The forever Function
The forever function takes an I/O action and returns an I/O action, and repeats the I/O action forever
To use the forever function, we need to import Control.Monad
This program will as a user for his/her name forever:
import Control.Monad
main = forever (do
putStrLn “What is your name?”
name <- getLine putStrLn ("Hello " ++ name)) Input and Output Thumrongsak Kosiyatrakul The forM Function The forM function is similar to the mapM function, but its parameters are switched The first argument is a list The second argument is a function to map over the list Often time, if the function to map over the list is pretty long, put it at the end of an expression will make the code easier to read Input and Output Thumrongsak Kosiyatrakul I/O Action I/O actions are values in Haskell We can pass them as arguments Functions can return I/O actions as result I/O actions are performed if they fall into the main function (or in GHCi) The do block is used to glue multiple I/O actions into one and the type of the block is the type of the last I/O action Input and Output Thumrongsak Kosiyatrakul