Lecture: Haskell Mains
Dear students:
The way to get better at new things is to actively throw yourself at them. Haskell's IO system and immutability is different, so we'll spend this lecture throwing ourselves at a series of small problems that require input and output.
power2
Write a program that asks the user for a integer \(n\) and prints \(2^n\).
Here's one possible solution:
main = do
text <- getLine
let n = read text :: Int
print $ 2 ^ n
multiplier
Write a program that multiplies two numbers entered by the user.
Here's one possible solution:
main = do
lineX <- getLine
let x = read lineX :: Int
lineY <- getLine
let y = read lineY :: Int
print $ x * y
span
Write a program that receives a bunch of integers as command-line arguments. It prints the range of the numbers. For example:
> runhaskell main.hs 7 3 80 9
3-80
Here's one possible solution:
import System.Environment
stringsToInts :: [String] -> [Int]
stringsToInts strings =
if null strings then
[]
else
i : stringsToInts rest
where
first = head strings
rest = tail strings
i = read first :: Int
main = do
args <- getArgs
let sortedArgs = sort $ stringsToInts args
let alpha = head sortedArgs
let omega = last sortedArgs
putStrLn $ show alpha ++ "-" ++ show omega
In a week's time, we are going to write this much shorter program:
main = do
args <- getArgs
let sortedArgs = sort $ map read args :: [Int]
let alpha = head sortedArgs
let omega = last sortedArgs
putStrLn $ show alpha ++ "-" ++ show omega
sum
Write a program that prints an equation summing up the command-line arguments. One side shows the addition expression, while the other shows the total.
Here's one possible solution:
import System.Environment
import Data.List
stringsToInts :: [String] -> [Int]
stringsToInts ss =
if null ss then
[]
else
(read $ head ss :: Int) : (stringsToInts $ tail ss)
main = do
args <- getArgs
putStr $ intercalate " + " args
putStr " = "
print $ sum $ stringsToInts args
number
Write a program that echoes the lines of a file, prefixing each line with its number. The file path is passed as a command-line argument.
Here's one possible solution:
import System.Environment
printNumberedLines :: Int -> [String] -> IO ()
printNumberedLines i lines =
if null lines then
return ()
else do
putStr $ show i
putStr " "
putStrLn $ head lines
printNumberedLines (i + 1) $ tail lines
main = do
args <- getArgs
let path = head args
text <- readFile path
let rows = lines text
printNumberedLines 0 rows
cat
Write a program like cat
that dumps all files passed as command-line arguments to standard out.
Here's one possible solution:
import System.Environment
catFiles :: [String] -> IO ()
catFiles files = do
if null files then
return ()
else do
text <- readFile $ head files
putStr text
catFiles $ tail files
main = do
args <- getArgs
catFiles args
spell
Write a program that spells out the phrase passed as a command-line argument, one character at a time. Use the say
utility, which is builtin on macOS. Linux has espeak
. I don't know about Windows.
Here's one possible solution:
import System.Environment
import System.Process
spell :: String -> IO ()
spell chars =
if null chars then
return ()
else do
if head chars == ' ' then
system $ "say space"
else do
system $ "say " ++ [head chars]
spell $ tail chars
main = do
args <- getArgs
let chars = head args
spell chars
Advent of Code 2015, Day 1
Write a program that solves Advent of Code 2015, Day 1. Accept the input text as a command-line argument.
Here's one possible solution:
import System.Environment
deliver :: String -> Int -> Int
deliver directions floor =
if directions == "" then
floor
else
deliver rest floor'
where
first = head directions
rest = tail directions
offset = if first == '(' then 1 else -1
floor' = floor + offset
main = do
args <- getArgs
let directions = head args
print $ deliver directions 0
Note that this follows the fold pattern. We could write a much simpler solution using tools we discuss next week.
TODO
Here's your list of things to do before we meet next:
See you next time.
Sincerely,
P.S. It's time for a haiku!