Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages...

50
Lecture 7: Monads and IO Søren Haagerup Department of Mathematics and Computer Science University of Southern Denmark, Odense December 7, 2015 Some slides of this presentation are borrowed from http://foswiki.cs.uu.nl/foswiki/pub/USCS/CourseSchedule/ C2-Monads-final.pdf

Transcript of Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages...

Page 1: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Lecture 7: Monads and IO

Søren Haagerup

Department of Mathematics and Computer ScienceUniversity of Southern Denmark, Odense

December 7, 2015

Some slides of this presentation are borrowed fromhttp://foswiki.cs.uu.nl/foswiki/pub/USCS/CourseSchedule/

C2-Monads-final.pdf

Page 2: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Introduction• Monads are central to modern Haskell programming.• The IO type class is an example of a monad. Code written

with this monad is evaluated sequentially, and can makeuse of the IO operations of the Operating System:

main = docolors← forM [1, 2, 3, 4 ] (λa→ do

putStrLn ("Which color do you associate "

++ "with the number "++ show a ++ "?")

color← getLinereturn color)

putStrLn ("The colors that you associate "

++ "with 1, 2, 3 and 4 are: ")

mapM putStrLn colors

Page 3: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Monadic computations often have special syntax...Haskell

pairs = do x← xsy← ysreturn (x, y)

Scala

val pairs = for { x← xsy← ys

} yield (x, y)

C# (LINQ)

var pairs = from x in xsfrom y in ysselect new {x, y};

Page 4: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Asynchronous computationControl.Monad.Par

dofx← spawn (return (f x)) -- start evaluating (f x)gx← spawn (return (g x)) -- start evaluating (g x)a← get fx -- wait for fxb← get gx -- wait for gxreturn (a, b) -- return results

“Futures/promises” which exist in many languages, fit nicelyinto the monad abstraction.f and g could be functions doing a HTTP POST request, ordoing an expensive computation.

Page 5: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Pure vs. impure languages• Monads can also help with making Haskell code shorter

and easier to read and write. This is the focus in thebeginning of this lecture.

• Pure languages• easy to reason about (equational reasoning)• may benefit from lazy evaluation,

• Impure languages• offer efficiency benefits• sometimes make possible a more compact mode of

expression

Using monads is an approach to integrate impure effects intopure programs.“In short, Haskell is the world’s finest imperative programminglanguage”

– Simon Peyton Jones

Page 6: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Problems with pure functional programming

• Pure functional languages have this advantage: All flow ofdata is made explicit.

• And this disadvantage: Sometimes it is painfully explicit.

• The essence of an algorithm can become buried under theplumbing required to carry data from its point of creationto its point of use.

• We will now exemplify these statements, and later proposesolutions based on monads.

Page 7: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Running example: A small interpreterWe introduce the type of terms, and an evaluation function:

data Term = Con Int | Div Term Term deriving Show

eval :: Term→ Inteval (Con a) = aeval (Div t u) = eval t ‘div‘ eval u

Examples of terms

answer, err :: Termanswer = (Div (Div (Con 1972) (Con 2)) (Con 23))err = (Div (Con 1) (Con 0))

We can evaluate...

eval answer = 42eval err = ⊥

Page 8: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Extension 1/3: Adding error handling

data Term = Con Int | Div Term Term deriving Show

eval :: Term→ Inteval (Con a) = aeval (Div t u) = eval t ‘div‘ eval u

• We would like to add error handling to eval, such that theprogram will not crash when dividing by zero, but insteadreturn an error that can be used by other parts of theprogram.

• In impure languages, we would throw an exception

• What can we do in Haskell?

Page 9: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Extension 1/3: Adding error handlingWe would like errors to be a value, and not ⊥:

data Error a = Raise Exception | Return a deriving Showtype Exception = String

eval :: Term→ Error Inteval (Con a) = Return aeval (Div t u) = case eval t of

Raise e→ Raise eReturn a→

case eval u ofRaise e→ Raise eReturn b→

if b ≡ 0then Raise "divide by zero"

else Return (a ‘div‘ b)

Page 10: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Extension 2/3: Adding state - Counting the number ofoperations performed

data Term = Con Int | Div Term Term deriving Show

eval :: Term→ Inteval (Con a) = aeval (Div t u) = eval t ‘div‘ eval u

• We would like to add a a count of operations performedby the evaluation engine.

• In impure languages: increment a global variable

• What can we do in Haskell?

Page 11: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Extension 2/3: Adding state - Counting the number ofoperations performed

type State s a = s→ (a, s)

eval :: Term→ State Int Inteval (Con a) x = (a, x)eval (Div t u) x = let (a, y) = eval t x in

let (b, z) = eval t y in(a ‘div‘ b, z + 1)

> eval answer 0(42, 2)

Page 12: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Extension 3/3: Adding an execution tracedata Term = Con Int | Div Term Term deriving Show

eval :: Term→ Inteval (Con a) = aeval (Div t u) = eval t ‘div‘ eval u

• We would like to add an execution trace to the program -and write out which calls are made to eval, and what aretheir arguments?

• In impure languages: Execute a print statement inside eval• How yould we do in Haskell?

> putStrLn $ fst $ eval answereval (Con 1972) = 1972eval (Con 2) = 2eval (Div (Con 1972) (Con 2)) = 986eval (Con 23) = 23eval (Div (Div (Con 1972) (Con 2)) (Con 23)) = 42

Page 13: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Adding an execution trace

type Writer a = (Output, a)type Output = String

eval :: Term→Writer Inteval (Con a) = (line (Con a) a, a)eval (Div t u) = let (x, a) = eval t in

let (y, b) = eval u in(x ++ y ++ line (Div t u) (a ‘div‘ b), a ‘div‘ b)

line :: Term→ Int→ Outputline t a = "eval ("++ show t ++ ") = "++ show a ++ "\n"

Page 14: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Adding an execution trace

> putStrLn $ fst $ eval answereval (Con 1972) 6 1972eval (Con 2) 6 2eval (Div (Con 1972) (Con 2)) 6 986eval (Con 23) 6 23eval (Div (Div (Con 1972) (Con 2)) (Con 23)) 6 42

> putStrLn $ fst $ eval erreval (Con 1) 6 1eval (Con 0) 6 0eval (Div (Con 1) (Con 0)) 6 ∗ ∗ ∗Exception : divide by zero

Page 15: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Adding an execution trace• From the discussion so far, it may appear that programs in

impure languages are easier to modify than those in purelanguages.

• But sometimes the reverse is true.• Say that it was desired to modify the previous program to

display the execution trace in the reverse order:

(x ++ y ++ line (Div t u) (a ‘div‘ b), a ‘div‘ b)

could be changed to

(line (Div t u) (a ‘div‘ b) ++ y ++ x, a ‘div‘ b)

• So - explicit data flow gives flexibility, but sometimes theexplicit way of programming is too explicit and buries theessence of the algoritm being implemented.

Page 16: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

What is a monad?

A monad is a triple (M, return, (>>=)) where

• M is a type constructor

• return :: a→M a is a function (also called unit)

• (>>=) :: M a→ (a→M b)→M b is a function (also calledbind)

Page 17: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

The old code

data Error a = Raise Exception | Return a deriving Showtype Exception = String

eval :: Term→ Error Inteval (Con a) = Return aeval (Div t u) = case eval t of

Raise e→ Raise eReturn a→

case eval u ofRaise e→ Raise eReturn b→

if b ≡ 0then Raise "divide by zero"

else Return (a ‘div‘ b)

Page 18: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

The new code

data Error a = Raise Exception | Return a deriving Showtype Exception = String

eval :: Term→ Error Inteval (Con a) = return aeval (Div t u) = do a← eval t

b← eval uif b ≡ 0

then raise "Divide by zero"

else return (a ‘div‘ b)

raise :: Exception→ Error araise e = Raise e

Page 19: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

The Error monad

data Error a = Raise Exception | Return a deriving Showtype Exception = String

instance (Monad Error) wherereturn = Returnm>>= k = case m of

Return a→ k aRaise e → Raise e

Verify the types• return :: a→ Error a• (>>=) :: Error a→ (a→ Error b)→ Error b

Question: How would you define a function f such that(Return x)>>= f = Return (x + 5) Note that we need nohandling of errors in the input given to f .

Page 20: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

The do notation

The do-notation

val = do a← eval tb← eval ureturn (a + b)

is just syntactic sugar for

val = eval t>>= λa→eval u>>= λb→return (a + b)

Page 21: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

How to define a monad for Maybe?

A simpler version of what we have just seen is:

data Maybe a = Nothing | Just a

Try to suggest definitions of the following functions:

• return :: a→Maybe a

• (>>=) :: Maybe a→ (a→Maybe b)→Maybe b

Page 22: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Introducing state - The old code

type State s a = s→ (a, s)

eval :: Term→ State Int Inteval (Con a) x = (a, x)eval (Div t u) x = let (a, y) = eval t x in

let (b, z) = eval t y in(a ‘div‘ b, z + 1)

Page 23: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

What we would like to end up with...

type State s a = s→ (a, s)

eval :: Term→ State Int Inteval (Con a) = return aeval (Div t u) = do a← eval t

b← eval utickreturn (a ‘div‘ b)

Notice that the counting is done with the function tick, andkeeping track of the state variable is done behind the scenes!But we cannot exactly achieve this with standard Haskell.

We would need to activate the TypeSynonymInstancescompiler pragma, to declare State s as a Monad instance.

Page 24: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

type State s a = s→ (a, s)

return a = λx→ (a, x)m>>= k = λx→ let (a, y) = m x in

let (b, z) = k a y in(b, z)

tick :: State s ()tick = λx→ ((), x + 1)

eval :: Term→ State Int Inteval (Con a) = return aeval (Div t u) = eval t>>= λa→

eval u >>= λb→tick >>= \ →return (a ‘div‘ b)

> eval answer 0(42, 2)

Page 25: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Making it an instance of Monad

For technical reasons, we need a newtype instead of anordinary type synonym type

newtype State s a = State {runState :: s→ (a, s)}

instance (Monad (State s)) wherereturn a = State (λx→ (a, x))m>>= k = State (λx→ let (a, y) = runState m x in

let (b, z) = runState (k a) y in(b, z))

tick :: M ()

tick = State (λx→ ((), x + 1))

Page 26: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

So we end up with the nice code that we wanted

eval :: Term→ State Int Inteval (Con a) = return aeval (Div t u) = do a← eval t

b← eval u← tick

return (a ‘div‘ b)

> runState (eval answer) 0(42, 2)

The do notation allows us to remove the ← (values which arethrown away)

Page 27: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

So we end up with the nice code that we wanted

eval :: Term→ State Int Inteval (Con a) = return aeval (Div t u) = do a← eval t

b← eval utickreturn (a ‘div‘ b)

> runState (eval answer) 0(42, 2)

Page 28: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Example from testrun.hs in the Exam ProjectrandomTake :: Int→ [a]→ State StdGen ([a ], [a])randomTake m xs = randomElems (length xs) m xs

whererandomElem :: Int→ [a]→ State StdGen (a, [a ])randomElem n xs = do

i← state $ randomR (0, n − 1)let (ys, ys ′) = splitAt i xsreturn (xs !! i, ys ++ drop 1 ys ′)

randomElems :: Int→ Int→ [a ]→ State StdGen ([a], [a ])randomElems n m xs | m 6 0 ∨ n 6 0 = return ([ ], xs)randomElems n m xs = do

(y, xs ′)← randomElem n xs(ys, xs ′′)← randomElems (n − 1) (m − 1) xs ′

return (y : ys, xs ′′)

Page 29: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Final variant: Adding execution trace

type M a = (Output, a)type Output = String

eval :: Term→M Inteval (Con a) = (line (Con a) a, a)eval (Div t u) = let (x, a) = eval t in

let (y, b) = eval u in(x ++ y ++ line (Div t u) (a ‘div‘ b), a ‘div‘ b)

line :: Term→ Int→ Outputline t a = "eval("++ show t ++ ")="++ show a ++ "\n"

Page 30: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

The code that we want to end up with...

eval :: Term→M Inteval (Con a) = do out (line (Con a) a)

return a

eval (Div t u) = do a← eval tb← eval uout (line (Div t u) (a ‘div‘ b))return (a ‘div‘ b)

Page 31: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

The definition of the monad...

type M a = (Output, a)type Output = String

return a = ("", a)m>>= k = let (x, a) = m in

let (y, b) = k a in(x ++ y, b)

out :: Output→M ()

out x = (x, ())

Page 32: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Technicalities - introducing a newtype

newtype M a = Writer {runWriter :: (Output, a)}type Output = String

instance (Monad M) wherereturn a = Writer ("", a)m>>= k = let Writer (x, a) = m in

let Writer (y, b) = k a inWriter (x ++ y, b)

out :: Output→M ()

out x = Writer (x, ())

Page 33: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Questions

Recall that a monad is a triple (M, return, (>>=)) where

return :: a→M a(>>=) :: M a→ (a→M b)→M b

Suggest definitions for (>>=) and return for the following typeconstructors:

• data Id a = Id a

• data [a ] = [ ] | a : [a ]

• data Tree a = Tip a | Node (Tree a) (Tree a)

Page 34: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

The List monad

Encoding multiple results and nondeterminism

Get the length of all words in a list of multi-line texts:

map length (concat (map words (concat (map lines txts))))

Easier to understand with a list comprehension:

[ length w | t← txts, l← lines t, w← words l]

We can also define sequencing and embedding, i.e., (>>=) andreturn :

(>>=) :: [a]→ (a→ [b ])→ [b]xs>>= f = concat (map f xs)return :: a→ [a ]return x = [x]

Page 35: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Four equivalent pieces of code

map length (concat (map words (concat (map lines txts))))

[ length w | t← txts, l← lines t, w← words l]

do t← txtsl← lines tw← words lreturn (length w)

txts >>= λt→lines t >>= λl→words l>>= λw→return (length w)

Page 36: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Adding filter functionalityodds = [x | x← [1 . . 10 ], odd x]

odds ′ = do x← [1 . . 10 ]-- how to filter odd x?

return x

odds ′ = do x← [1 . . 10 ]← if (odd x) then [()] else [ ]

return x

import Control.Monadodds ′ = do x← [1 . . 10 ]

guard (odd x)return x

Page 37: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

The Monad Laws

class Monad m wherereturn :: a→ m a(>>=) :: m a→ (a→ m b)→ m b

• The name “monad” is borrowed from category theory.

• A monad is an algebraic structure similar to a monoid.

• Monads have been popularized in functionalprogramming via the work of Moggi and Wadler.

• Every monad instance should satisfy the following laws:1. Left identity: return x>>= k ≡ k x2. Right identity: m>>= return ≡ m3. Associativity: m>>= (λa→ k a>>= l) ≡ (m>>= k)>>= l

Page 38: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

The IO Monad

Another type with actions that require sequencing. The IOmonad is special in several ways:

• IO is a primitive type, and (>>=) and return for IO areprimitive functions,

• I there is no (politically correct) function runIO :: IO a→ a,whereas for most other monads there is a correspondingfunction,

• values of IO a denote side-effecting programs that can beexecuted by the run-time system.

• Note that the specialty of IO has really not much to dowith being a monad.

Page 39: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

IO, Internally

Prelude> :i IOnewtype IO a

= GHC.Types.IO (GHC.Prim.State # GHC.Prim.RealWorld→ (#GHC.Prim.State # GHC.Prim.RealWorld, a#))

-- Defined in ‘GHC.Types’instance Monad IO -- Defined in ‘GHC.Base’instance Functor IO -- Defined in ‘GHC.Base’

Internally, GHC models IO as a state monad having the “realworld” as state!

Page 40: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

The role of IO in Haskell

More and more features have been integrated into IO, forinstance:

• classic file and terminal IOputStr, hPutStr

• referencesnewIORef , readIORef , writeIORef

• access to the systemgetArgs, getEnvironment, getClockTime

• exceptionsthrowIO, catch

• concurrencyforkIO

Page 41: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

IO examples

Stdout output

Main> putStr "Hi"HiMain> do {putChar ’H’; putChar ’i’; putChar ’\n’}Hi

Stdin input

Main> do {c← getChar; putStrLn ("’"++ [c ] ++ "’")}

z ′z ′

Page 42: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

IO examples

File IO

Main> do {h← openFile "TMP" WriteMode; hPutStrLn h "Hi"}Main> :q

Leaving GHCi

$ cat TMP

Hi

Page 43: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

IO examples

Side-effect: variables

do v← newIORef "text"modifyIoRef v (λt→ t ++ " and more text")

w← readIORef vprint w

Results in text and more text

Page 44: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

The role of IO in Haskell (contd.)

• A program that involves IO in its type can do everything.The absence of IO tells us a lot, but its presence does notallow us to judge what kind of IO is performed.

• It would be nice to have more fine-grained control on theeffects a program performs.

• For some, but not all effects in IO, we can use or buildspecialized monads.

Page 45: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Lifting functions to monads

liftM :: (Monad m)⇒ (a→ b)→ m a→ m bliftM2 :: (Monad m)⇒ (a→ b→ c)→ m a→ m b→ m c. .liftM f m = do {x← m; return (f x)}liftM2 f m1 m2 = do {x1← m1; x2← m2; return (f x1 x2)}. .

Question: What is liftM (+1) [1 . . 5 ] ? Answer: Same asmap (+1) [1 . . 5 ]. The function liftM generalizes map to arbitrarymonads.

Page 46: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Monadic map

mapM :: (Monad m)⇒ (a→ m b)→ [a ]→ m [b]mapM :: (Monad m)⇒ (a→ m b)→ [a]→ m ()

mapM f [ ] = return [ ]

mapM f (x : xs) = liftM2 (:) (f x) (mapM f xs)mapM f [ ] = return ()

mapM f (x : xs) = f x>>mapM f xs

Page 47: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Sequencing monadic actions

sequence :: (Monad m)⇒ [m a]→ m [a ]sequence :: (Monad m)⇒ [m a]→ m ()

sequence = foldr (liftM2 (:)) (return [ ])

sequence = foldr (>>) (return ())

Page 48: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Monadic fold

foldM :: (Monad m)⇒ (a→ b→ m a)→ a→ [b ]→ m afoldM op e [ ] = return efoldM op e (x : xs) = do r← op e xfoldM f r xs

Page 49: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

More monadic operations

Browse Control.Monad :

filterM :: (Monad m)⇒ (a→ m Bool)→ [a]→ m [a ]replicateM :: (Monad m)⇒ Int→ m a→ m [a]replicateM :: (Monad m)⇒ Int→ m a→ m ()

join :: (Monad m)⇒ m (m a)→ m awhen :: (Monad m)⇒ Bool→ m ()→ m ()

unless :: (Monad m)⇒ Bool→ m ()→ m ()

forever :: (Monad m)⇒ m a→ m ()

. . . and more!

Page 50: Lecture 7: Monads and IOshaagerup.github.io/dm552/2015/files/lec7.pdfPure vs. impure languages Monads can also help with making Haskell code shorter and easier to read and write. This

Exercises Wednesday

• Will be relevant for the exam project.

• minimax and expectimax will be discussed.

• Different tree algorithms on “Game trees”

• The exercises next week will be on Real World Haskell

• The labs on friday next week will be about monadproblems, but you can also work on your project.