Monadic Programming Arvind Computer Science and Artificial Intelligence

  • Slides: 31
Download presentation
Monadic Programming Arvind Computer Science and Artificial Intelligence Laboratory M. I. T. October 26,

Monadic Programming Arvind Computer Science and Artificial Intelligence Laboratory M. I. T. October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -

Outline • IO Monad – Example: wc program – Some properties • Monadic laws

Outline • IO Monad – Example: wc program – Some properties • Monadic laws • Creating our own monads: – – – October 26, 2006 Id: The simplest monad State Unique name generator Emulating simple I/O Exceptions http: //www. csg. csail. mit. edu/6. 827 L 13 -2

Monadic I/O IO a: computation which does some I/O, then produces a value of

Monadic I/O IO a: computation which does some I/O, then produces a value of type a. (>>) : : IO a -> IO b (>>=) : : IO a -> (a -> IO b) -> IO b return : : a -> IO a Primitive actionspecs: get. Char : : IO Char put. Char : : Char -> IO () open. File, h. Close, . . . Monadic I/O is a clever, type-safe idea which has become a rage in the FL community. October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -3

Word Count Program wcs : : String -> Bool -> (Int, Int) wcs []

Word Count Program wcs : : String -> Bool -> (Int, Int) wcs [] in. Word (nc, nw, nl) = (nc, nw, nl) wcs (c: cs) in. Word (nc, nw, nl) = if (is. New. Line c) then wcs cs False ((nc+1), nw, (nl+1)) else if (is. Space c) then wcs cs False ((nc+1), nw, nl) else if (not in. Word) then wcs cs True ((nc+1), (nw+1), nl) else wcs cs True ((nc+1), nw, nl) Can we read the string from an input file as needed? October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -4

File Handling Primitives type Filepath = String data IOMode = Read. Mode | Write.

File Handling Primitives type Filepath = String data IOMode = Read. Mode | Write. Mode |. . . data Handle =. . . implemented as built-in type open. File h. Close h. Is. EOF h. Get. Char October 26, 2006 : : : : File. Path -> IOMode -> IO Handle -> IO () Handle -> IO Bool Handle -> IO Char http: //www. csg. csail. mit. edu/6. 827 L 13 -5

Monadic Word Count Program file name wc : : String -> IO (Int, Int)

Monadic Word Count Program file name wc : : String -> IO (Int, Int) wc filename = open. File filename Read. Mode >>= h -> wch h False (0, 0, 0) >>= (nc, nw, nl) -> h. Close h >> return (nc, nw, nl) wch wcs October 26, 2006 : : Handle -> Bool -> (Int, Int) -> IO (Int, Int) : : String -> Bool -> (Int, Int) http: //www. csg. csail. mit. edu/6. 827 L 13 -6

Monadic Word Count Program cont. wch : : Handle -> Bool -> (Int, Int)

Monadic Word Count Program cont. wch : : Handle -> Bool -> (Int, Int) -> IO (Int, Int) wch h in. Word (nc, nw, nl) = h. Is. EOF h >>= eof -> if eof then return (nc, nw, nl) else h. Get. Char h >>= c -> if (is. New. Line c) then wch h False ((nc+1), nw, (nl+1)) else if (is. Space c) then wch h False ((nc+1), nw, nl) else if (not in. Word) then wch h True ((nc+1), (nw+1), nl) else wch h True ((nc+1), nw, nl) October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -7

Calling WC main : : IO () main = get. Args >>= [filename] ->

Calling WC main : : IO () main = get. Args >>= [filename] -> wc filename >>= (nc, nw, nl) -> put. Str “ ” >> put. Str (show nc) >> put. Str “ ” >> put. Str (show nw) >> put. Str “ ” >> put. Str (show nl) >> put. Str “ ” >> put. Str filename >> put. Str “n” Once a value enters the IO monad it cannot leave it! October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -8

Error Handling Monad can abort if an error occurs. Can add a function to

Error Handling Monad can abort if an error occurs. Can add a function to handle errors: catch : : IO a -> (IOError -> IO a) -> IO a io. Error : : IOError -> IO a fail : : String -> IO a catch echo (err -> fail (“I/O error: ”++show err)) October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -9

The Modularity Problem Inserting a print (say for debugging): sqrt : : Float ->

The Modularity Problem Inserting a print (say for debugging): sqrt : : Float -> IO Float sqrt x = let. . . a = (put. Str. Ln. . . ) : : IO String in a >> return result Without the binding has no effect; the I/O has to be exposed to the caller: One print statement changes the whole structure of the program! October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -10

Monadic I/O is Sequential wc filename 1 >>= (nc 1, nw 1, nl 1)

Monadic I/O is Sequential wc filename 1 >>= (nc 1, nw 1, nl 1) -> wc filename 2 >>= (nc 2, nw 2, nl 2) -> return (nc 1+nc 2, nw 1+nw 2, nl 1+nl 2)! The two wc calls are totally independent but the IO they perform must be sequentialized! Monadic I/O is not conducive for parallel operations October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -11

Syntactic sugar: do do e -> e do e ; dostmts -> e >>

Syntactic sugar: do do e -> e do e ; dostmts -> e >> do dostmts do p<-e ; dostmts -> e >>= p-> do dostmts do let p=e ; dostmts -> let p=e in do dostmts wc filename 1 >>= (nc 1, nw 1, nl 1) -> wc filename 2 >>= (nc 2, nw 2, nl 2) -> return (nc 1+nc 2, nw 1+nw 2, nl 1+nl 2) versus do (nc 1, nw 1, nl 1) <- wc filename 1 (nc 2, nw 2, nl 2) <- wc filename 2 return (nc 1+nc 2, nw 1+nw 2, nl 1+nl 2) October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -12

Are these program meaningful? do (nc 1, nw 1, nl 1) <- wc filename

Are these program meaningful? do (nc 1, nw 1, nl 1) <- wc filename 1 (nc 2, nw 2, nl 2) <- wc filename 1 return (nc 1+nc 2, nw 1+nw 2, nl 1+nl 2) foo = wc filename 1 do (nc 1, nw 1, nl 1) <- foo (nc 2, nw 2, nl 2) <- foo return (nc 1+nc 2, nw 1+nw 2, nl 1+nl 2) October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -13

Monadic Laws 1. do x <- return a ; m (x -> do m)

Monadic Laws 1. do x <- return a ; m (x -> do m) a 2. do x <- m ; return x m 3. do y <- (do x <- m ; n) ; o do x <- m; (do y <- n; o) x FV(o) True for all monads. Only primitive operations distinguish monads from each other do m ; n do _ <- m ; n A derived axiom: m >> (n >> o) (m >> n) >> o October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -14

Properties of programs involving IO put. String [] = return () put. String (c:

Properties of programs involving IO put. String [] = return () put. String (c: cs) = put. Char c >> put. String cs [] ++ bs (a: as) ++ bs = a : (as ++ bs) put. String as >> put. String bs put. String (as++bs) One can prove this just using monadic laws without involving I/O properties October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -15

Monads and Let 1. do x <- return a ; m (x -> do

Monads and Let 1. do x <- return a ; m (x -> do m) a 2. do x <- m ; return x m 3. do y <- (do x <- m ; n) ; o do x <- m; (do y <- n; o) x FV(o) 1. let x = a in m (x -> m) a 2. let x = m in x m 3. let y = (let x = m in n) in o let x = m in (let y = n in o) x FV(o) Monadic binding behaves like let October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -16

Monads and Let • Relationship between monads and let is deep • This is

Monads and Let • Relationship between monads and let is deep • This is used to embed languages inside Haskell • IO is a special sublanguage with side effects class Monad return : : (>>=) : : (>>) : : fail : : October 26, 2006 m where a -> m a -> (a -> m b) -> m b m a -> m b String -> m a --* http: //www. csg. csail. mit. edu/6. 827 L 13 -17

Fib in Monadic Style fib n = if (n<=1) then n else let n

Fib in Monadic Style fib n = if (n<=1) then n else let n 1 = n - 1 n 2 = n - 2 f 1 = fib n 1 f 2 = fib n 2 in f 1 + f 2 fib n = if (n<=1) then return n else do n 1 <- return (n-1) n 2 <- return (n-2) f 1 <- fib n 1 f 2 <- fib n 2 return (f 1+f 2) Note the awkward style: everything must be named! October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -18

Outline • IO Monad – Example: wc program – Some properties • Monadic laws

Outline • IO Monad – Example: wc program – Some properties • Monadic laws • Creating our own monads: – – – October 26, 2006 Id: The simplest monad State Unique name generator Emulating simple I/O Exceptions http: //www. csg. csail. mit. edu/6. 827 L 13 -19

Id: The Simplest Monad newtype Id a = Id a instance Monad Id where

Id: The Simplest Monad newtype Id a = Id a instance Monad Id where return a = Id a >>= f a run. Id (Id a) = a • This monad has no special operations! • Indeed, we could just have used let • The run. Id operation runs our computation For IO monad run was done outside the language October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -20

The State Monad • Allow the use of a single piece of mutable state

The State Monad • Allow the use of a single piece of mutable state put : : s -> State s () get : : State s s run. State : : s -> State s r -> (s, r) instance Monad (State s) October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -21

The State Monad: Implementation newtype State s r = S (s -> (s, r))

The State Monad: Implementation newtype State s r = S (s -> (s, r)) instance Monad (State s) where return r = S (s -> (s, r)) S f >>= g = S (s -> let (s’, r) = f s S h = g r in h s’) get = S (s -> (s, s)) put s = S (o -> (s, ()) run. State s (S c) = c s October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -22

Generating Unique Identifiers type Uniq = Int type Uniq. M = State Int run.

Generating Unique Identifiers type Uniq = Int type Uniq. M = State Int run. Uniq. M : : Uniq. M r -> r run. Uniq. M comp = snd (run. State 0 comp) uniq : : Uniq. M Uniq uniq = do u <- get put (u+1) return u October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -23

Poor Man’s I/O type Poor. IO a = State (String, String) put. Char :

Poor Man’s I/O type Poor. IO a = State (String, String) put. Char : : Char -> Poor. IO () put. Char c = do (in, out) <- get put (in, out++[c]) get. Char : : Poor. IO Char get. Char = do (in, out) <- get case in of a: as -> do put (as, out) return a [] -> fail “EOF” October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -24

Error Handling using Maybe instance Monad Maybe where return a = Just a Nothing

Error Handling using Maybe instance Monad Maybe where return a = Just a Nothing >>= f = Nothing Just a >>= f a fail _ = Nothing Just a `mplus` b = Just a Nothing `mplus` b = b do m’ <- matrix. Inverse m y <- matrix. Vect. Mult m x return y October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -25

Combining Monads • To simulate I/O, combine State and Maybe. • There are two

Combining Monads • To simulate I/O, combine State and Maybe. • There are two ways to do this combination: newtype SM s a = SM (s -> (s, Maybe a)) newtype MS s a = MS (s -> Maybe (s, a)) do put. Char ‘H’ a <- get. Char Nothing put. Char ‘I’ `mplus` put. Char ‘!’ October 26, 2006 SM MS ([], ””) ([], ”H”) skipped ([], ”H!”) ([], ”!”) http: //www. csg. csail. mit. edu/6. 827 L 13 -26

Special Monads • Operations inexpressible in pure Haskell • IO Monad Primitives must actually

Special Monads • Operations inexpressible in pure Haskell • IO Monad Primitives must actually call the OS Also used to embed C code • State Transformer Monad Embeds arbitrary mutable state Alternative to M-structures + barriers October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -27

Extras October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -28

Extras October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -28

Monadic Laws 1. return a >>= x -> m (x -> m) a 2.

Monadic Laws 1. return a >>= x -> m (x -> m) a 2. m >>= x -> return x m 3. (m >>= x -> n) >>= y -> o m >>= x -> (n >>= y -> o) x FV(o) True in every monad by definition. Primitive monadic operators distinguish one monad from another A derived axiom: m >> (n >> o) (m >> n) >> o October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -29

Base case put. String [] = return () [] = bs ++ bs put.

Base case put. String [] = return () [] = bs ++ bs put. String [] return () put. String October 26, 2006 >> put. String bs bs ([]++bs) http: //www. csg. csail. mit. edu/6. 827 L 13 -30

Inductive case put. String (a: as) = put. Char a >> put. String as

Inductive case put. String (a: as) = put. Char a >> put. String as (a: as) ++ bs = a : (as ++ bs) put. String (a: as) >> put. String bs (put. Char a >> put. String as) >> put. String bs put. Char a >> (put. String as>>put. String bs) put. Char a >> (put. String (as ++ bs)) put. String (a : (as ++ bs)) put. String ((a: as) ++ bs) October 26, 2006 http: //www. csg. csail. mit. edu/6. 827 L 13 -31