Topics in Advanced Computing Lesson 8: Input

  1. Questions?
  2. Catch-up
  3. Input
    1. IO Actions
    2. Lets
    3. Returns
    4. IO Functions
    5. When
    6. Others
    7. Conclusion

Questions?

Catch-up

Input

We haven’t done an actual “Hello World” program yet. We haven’t done the usual steps of creating a source file, compiling it, and running it. Let’s try that now. Create a new file called “hello.hs”:

main = putStrLn "Hello world!"

Two options:

  1. stack runhaskell hello.hs: runs it directly.
  2. stack ghc -- --make hello: compiles and links.

After option (2): we get an executable file just named “hello”, which we can then run using the command line ./hello. (On Windows, this might be “hello.exe”).

IO Actions

An IO action is something that will carry out an action with a side effect (in this case, an input/output side effect like reading data from the console or printing to the screen).

main = do
  putStrLn "Type in your name"
  name <- getLine
  putStrLn $ "Hi there " ++ name

The <- syntax is the instruction to perform the requested IO action and bind its value to the variable.

main = do
  result <- putStrLn "Hello" -- this works, but why?
  print result

Compile / run. What gets printed? Why? (What did putStrLn return again? IO ())

Lets

In a do block, we can have let bindings, with no in.

import Data.Char

main = do
    putStrLn "What's your first name?"
    firstName <- getLine
    putStrLn "What's your last name?"
    lastName <- getLine
    let bigFirstName = map toUpper firstName
        bigLastName = map toUpper lastName
    putStrLn $ "hey " ++ bigFirstName ++ " " ++ bigLastName ++ ", how are you?"

Q: <- vs let?

printTwo = putStrLn "Two" 

main = do 
  putStrLn "One" 
  let printFour= putStrLn "Four" 
      getMyLine = getLine 
      printThree = putStrLn "Three" 
  printTwo 
  printThree 
  putStr "Type something " 
  myLine <-getMyLine 
  printFour 
  putStrLn $ "You typed \"" ++ myLine ++ "\""

Word Reverser program:

reverseWords :: String -> String 
reverseWords = unwords . map reverse . words 

main = do 
  line <- getLine 
  if null line then 
    return () 
  else do
    putStrLn $ reverseWords line 
    main -- glue together two IO actions as one using do block.

if-then-else is an expression. Both branches must return the same type. What does return do?

Returns

main = do
  return "tree falls in a forest" -- no one is listening
  return () -- no control transfer
  a <- return "something " -- basically: let a = "something"
  b <- do
    return "silence"
    putStrLn "did we return?"
    return "else " -- binds else to b
  let c = "was returned"
  putStrLn $ a ++ b ++ c

IO Functions

When

when :: Bool -> IO () -> IO ()
when p s = if p then s else return ()

Basically an if without an else. So the earlier code could have been:

import Control.Monad (when)
reverseWords :: String -> String 
reverseWords = unwords . map reverse . words 

main = do 
  line <- getLine 
  when (not (null line)) $ do 
    putStrLn $ reverseWords line 
    main

unless is better than when (not...))

Others

Examples:

main= do 
  inputLines <- sequence $ replicate 10 getLine 
  mapM_ putStrLn inputLines
import Control.Monad

main = do
  colors <- forM [1..4] (\a -> do
    putStrLn $ "Pick a color for the number " ++ show ++ a
    getLine)
  forM_ colors putStrLn -- for each color in colors, putStrLn color

Conclusion