You can read about these subjects in Learn You a Haskell, chapters 8 and 9.
In Haskell, a do block is like a generalized list comprehension.
As a first example, we may use do
with ordinary lists. Consider this list comprehension:
> list = [(x, y) | x <- [1..2], y <- [1..3]] > list [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3)]
We may alternatively write it using do
notation:
list = do
x <- [1..2]
y <- [1..3]
return (x, y)
We see that in a do block, we can use
the <- operator to retrieve a
value. At the end of the do
block, we can use the return function to
produce a value to be
returned. When we use do with ordinary
lists, we retrieve values from lists, and the return values are
joined together into a list.
We may also use do
with Maybe. Here's a function that takes
three values of type (Maybe Int), and
returns their sum:
add :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int
add mx my mz = do
x <- mx
y <- my
z <- mz
return (x + y + z)Let's try it:
> add (Just 3) (Just 4) (Just 5) Just 12 > add (Just 3) Nothing (Just 5) Nothing
Notice that if any of the input values is absent, the result is
Nothing. To see why this is true, recall
that a Maybe behaves like a list that
has 0 or 1 elements, and notice that the following do
block will produce an empty list:
list = do
x <- [3]
y <- []
z <- [5]
return (x + y + z)
A do block with Maybe
values can be quite useful for error handling. Suppose that we want
to call several functions, any of which might fail and return
Nothing. If we place these calls in a do
block, then it will return Nothing if
any of the function calls failed.
As we saw in the lecture (and you can also read
about in Learn You a Haskell), do blocks
also work with I/O objects. In fact do
blocks will work with any instance of a type class called Monad,
which plays a fundamental role in advanced Haskell programming. [],
Maybe and IO
are all instances of Monad. In the next
lectures we'll learn more about the Monad
type class, and will learn how to make our own types that work with
do.
Write a Haskell program that reads a rectangular matrix of integers from standard input.
First solution:
import Data.List main :: IO () main = do s <- getContents let ls :: [String] = lines s let m :: [[String]] = map words ls let m' = transpose (reverse m) let t = unlines (map unwords m') putStr t
Solution using interact:
import Data.List main :: IO () main = interact (unlines . map unwords . transpose . reverse . map words . lines)
Write a Haskell program that is like the command-line utility 'grep'. It should take two command-line arguments: a string to search for, plus a filename. It should print out all lines in the file that contain the given string.
import Data.List
import System.Environment
main :: IO ()
main = do
args <- getArgs
case args of
[s, filename] -> do
text <- readFile filename
let matches = filter (isInfixOf s) (lines text)
putStr (unlines matches)
_ -> putStrLn "usage: runghc grep.hs <str> <filename>"import Data.List
import Data.Ord
data Move = Rock | Paper | Scissors
deriving Eq
type Strategy = [Move] -> Move
beats :: Move -> Move
beats Rock = Paper
beats Paper = Scissors
beats Scissors = Rock
-- a) Write a Strategy that plays whatever will beat the opponent's last move.
beats_last :: Strategy
beats_last (m : _) = beats m
-- b) Write a Strategy that chooses the move that the opponent
-- has played most often in the past, and plays whatever will beat that.
all_moves = [Rock, Paper, Scissors]
beats_most :: Strategy
beats_most moves =
let count move = length (filter (== move) moves) in
beats (maximumBy (comparing count) all_moves)import Data.List
-- a) Create a type Game representing the state of this game.
-- Also create a value start :: Game representing the initial state of the game.
type Pos = (Int, Int)
-- Bool: true if fox's turn to play
-- [Pos] = position of fox : positions of hounds
data Game = Game (Bool, [Pos])
start :: Game
start = Game (True, [(7, 0), (0, 1), (0, 3), (0, 5), (0, 7)])
-- b) Write a function show_game :: Game → String that produces
-- a visual representation of the board.
show_row_col :: Game -> Int -> Int -> String
show_row_col (Game (__, positions)) r c =
case elemIndex (r, c) positions of
Just 0 -> "F"
Just _ -> "H"
Nothing ->
if odd (r + c) then "." else " "
-- show 1 row of the game
show_row :: Game -> Int -> String
show_row game r =
unwords [show_row_col game r c | c <- [0..7]]
show_game :: Game -> String
show_game game = unlines [show_row game i | i <- [0..7]]