Programming Languages

Andrea Flexeder

Chair for Theoretical Computer Science Prof. Seidl TU Munchen¨

winter term 2010/2011 Lecture 10 Side-Effects Main Points you should get:

• Why monads?

• What is a monad?

• How to use a monad? ]: and side-effects

static bool LessThanThirty(int x) { Console.Write("<0>? Less than 30;",x); return x < 30; } static bool MoreThanTwenty(int x) { Console.Write("<0>? More than 20;",x); return x > 20; } var q0 = from x in new[]<1,25,40,5,23> where LessThanThirty(x) select x; var q1 = from x in q0 where MoreThanTwenty(x) select x;

foreach (var r in q1) Console.WriteLine("[<0>];",r); C]: Lazy evaluation and side-effects

Output: • 1? Less than 30; • 1? More than 20; • 25? Less than 30; • 25? More than 20; • 40? Less than 30; • 5? Less than 30; • ... Haskell

lessThanThirty x = do {putStrLn ((show x) ++ " less than 30?"); return (x < 30) }

moreThanTwenty x = do {putStrLn ((show x) ++ " more than 20?"); return (x > 20) } q0 = [x | x <- [1, 25, 50, 5, 23], lessThanThirty x] q1 = [x | x <- q0, moreThanTwenty x]

Couldn’t match expected type ‘Bool’ against inferred type ‘IO Bool’ In the expression: moreThanTwenty 20 In a stmt of a list comprehension: moreThanTwenty 20 In the expression: [x|x ← q0, moreThanTwenty 20] Side-Effects

Effect • besides producing a value, • modifying some state, • observable interaction with world/functions • e.g. global state, exception handling, I/O, non-determinism, . . . • ⇒ control flow matters!

Control Flow order in which actions/ calls are evaluated 2. monads aim: integrate impure side-effects into a pure functional language e.g. Haskell

Discussion

two ways of approaching effects in :

1. reference cells, sequence operator, functions with side-effect val x = ref 0 x := !x +1 print x e.g. Standard ML Discussion

two ways of approaching effects in functional programming:

1. reference cells, sequence operator, functions with side-effect val x = ref 0 x := !x +1 print x e.g. Standard ML 2. monads aim: integrate impure side-effects into a pure functional language e.g. Haskell Monadic Style

Characteristics: • make explicit sequence in which actions take place allows I/O operations in presence of laziness • usage of state dealing with global data objects crosscutting concerns: debugging, exception handling, etc. • concept from category theory • idea of E. Moggi (mathematical formalisation) • structuring denotational semantics • translated to functional programming by P. Wadler • alternative to CPS echoTwice :: IO () echoTwice = echo >> echo

echoDup :: IO () echoDup = getChar >>= \c -> putChar c >> putChar c

IO Example (1)

echo :: IO () echo = getChar >>= putChar IO Example (1)

echo :: IO () echo = getChar >>= putChar echoTwice :: IO () echoTwice = echo >> echo echoDup :: IO () echoDup = getChar >>= \c -> putChar c >> putChar c IO Example (2)

getTwoChars :: IO (Char, Char) getTwoChars = getChar >>= \c1 -> getChar >>= \c2 -> ??????? IO Example (2)

getTwoChars :: IO (Char, Char) getTwoChars = getChar >>= \c1 -> getChar >>= \c2 -> return (c1,c2) IO Monad

• type constructor IO denotes computations interacting with operating system • return :: a → IO a • (>>=) :: IO a → (a → IO b) → IO b • interpretation of type IO a: computation with I/O and a return value of type a • return value of a computation should only be used in further computations and not as return value of a function! Basic Definition

• type class Monad for monads with methods return and bind (>>=) • type constructor m • generation of a monad return :: Monad m => a → m a • takes some value x • yields a monadic operation having only x as return value • composition of monadic computations (>>=) :: Monad m => m a → (a → m b) → m b • 2nd computation uses return value of 1st computation • return value is return value of 2nd computation Monad Class

type constructor class

class Monad m :: (* → *) where (>>=) :: forall a b . m a → (a → m b) → m b (>>) :: forall a b . m a → m b → m b (return) :: forall a. a → m a (fail) :: String → m a m >> k = m >>= \ → k fail s = error s • each line in do-notation creates a new : • fun r = do x ← f r x ← g x x ← h x return x • fun r = f r >>= ((\x → g x) >>= ((\x → h x) >>= (\x → return x)))

Do Notation (Example)

• fun a = return a >>= (\b → (f b >>= (\c → g b c) )) • in do-notation: fun b = do { c ← f b; g b c } equivalent to: fun b = do c ← f b g b c Do Notation (Example)

• fun a = return a >>= (\b → (f b >>= (\c → g b c) )) • in do-notation: fun b = do { c ← f b; g b c } equivalent to: fun b = do c ← f b g b c • each line in do-notation creates a new scope: • fun r = do x ← f r x ← g x x ← h x return x • fun r = f r >>= ((\x → g x) >>= ((\x → h x) >>= (\x → return x))) • equivalent to: do x1 ← e1; x2 ← e2; e3; x4 ← e4; e5

Do Notation

• each e >>= \x → ... becomes x ← e; ... • each e >> ... becomes e; ... • e1 >>= \x1 → e2 >>= \x2 → e3 >> e4 >>= \x4 → e5 Do Notation

• each e >>= \x → ... becomes x ← e; ... • each e >> ... becomes e; ... • e1 >>= \x1 → e2 >>= \x2 → e3 >> e4 >>= \x4 → e5 • equivalent to: do x1 ← e1; x2 ← e2; e3; x4 ← e4; e5 IO Example (2) in Do-Notation

getTwoChars :: IO (Char, Char) getTwoChars = getChar >>= \c1 -> getChar >>= \c2 -> return (c1,c2) getTwoChars :: IO (Char,Char) getTwoChars = do { c1 <- getChar ; c2 <- getChar ; return (c1,c2) } IO in Haskell

• entire Haskell program is wrapped inside the IO monad • main program is an action of type IO () • example: main :: IO () main = do putStr "Your name: " x <- getLine putStr ("Hello "++ x ++".\n")

-- equivalent to main1 = putStr "Your name:" >>= \x -> getLine >>= \x -> putStr ("Hello "++ x ++".\n")

• reconcile effects and referential transparency, laziness • disciplined way to encapsulate states (imperative style) (>>=) and return satisfy the laws of a monad: return v >>= \x → m = m[x:=v] m >>= \x → return x = m (m >>= \x → n) >>= \y→ o = m >>= \x → (n >>= \y → o)

Monadic Laws

guarantee that monadic composition is associative and has left and right unit 1. (return a) >>= f =⇒ f a - - left unit 2. m >>= return =⇒ m - - right unit 3. (m >>= f ) >>= g =⇒ m >>= (\x → f x >>= g) - - associativity Monadic Laws

guarantee that monadic composition is associative and has left and right unit 1. (return a) >>= f =⇒ f a - - left unit 2. m >>= return =⇒ m - - right unit 3. (m >>= f ) >>= g =⇒ m >>= (\x → f x >>= g) - - associativity (>>=) and return satisfy the laws of a monad: return v >>= \x → m = m[x:=v] m >>= \x → return x = m (m >>= \x → n) >>= \y→ o = m >>= \x → (n >>= \y → o) • monoid examples:

• (N0, +, 0) • (Z, +, 0) • (N, ∗, 1) • (Σ∗, concat, ) • (a, (++), [ ])

Monoid

• algebraic structure (M, •, u): operator (•), value u, set M • operator has the value as identity u • x = x x • u = x • operator is associative ( x • y ) • z = x • (y • z) Monoid

• algebraic structure (M, •, u): operator (•), value u, set M • operator has the value as identity u • x = x x • u = x • operator is associative ( x • y ) • z = x • (y • z) • monoid examples:

• (N0, +, 0) • (Z, +, 0) • (N, ∗, 1) • (Σ∗, concat, ) • (a, (++), [ ]) Overview

some instances of monads: • IO • Identity • Exception • State • Maybe • List Example: Interpreter

Modularity and Extensibility: • Example: Interpreter • combination of interpreter and background information • enriched by following background info: 1. no: identity monad 2. errors: exception monad 3. operation counter: state monad Modification

• environment contains computations instead of values type Env = [(Variable,M Value)] update :: Env → Variable → M Value → Env

• replacing each function of type a → b by a function of type a → M b

• functions eval, add, myLookup have to be modified! Identity Monad

module MonIdent where newtype I a = I a deriving Show instance Monad I where return x = I x (I x) >>= f = f x fail i = error "lookup failed" printOut :: Show a => I a -> String printOut (I x) = show x Exceptions

Exceptions

• mechanism for interrupting normal control flow in program • signalling exceptional condition • exception: typed, diagnostic identifier 1. typed: you can define your own kinds of exception 2. diagnostic: you can tell something about the error Exceptions – Realisation

function f returns something – or fails • possibility 1: return Nothing • possibility 2: wrap every function application in a case to find out whether result is returned or exception • possibility 3: mechanism in language exception mechanisms:

1. exit(1) / atexit(...) 2. goto 3. setjmp/longjmp 4. raise/jump (catch/throw) and variations 5. callcc continuations • Attention: user might be interested in order of errors! 1. scenario1: division by zero prior to allocation fail assumption: i=0 ⇒ trying to allocate ∞ memory ⇒ 1 error 2. scenario2: allocation fail prior to division by zero assumption: < 512/i RAM available ∧ j=0 ⇒ 2 errors

Exceptions - Order matters!

• example: int i = ..., j = ...; malloc (512MB/i); ... int k = i/j; • situation: 1. allocation fail and 2. division by zero Exceptions - Order matters!

• example: int i = ..., j = ...; malloc (512MB/i); ... int k = i/j; • situation: 1. allocation fail and 2. division by zero • Attention: user might be interested in order of errors! 1. scenario1: division by zero prior to allocation fail assumption: i=0 ⇒ trying to allocate ∞ memory ⇒ 1 error 2. scenario2: allocation fail prior to division by zero assumption: < 512/i RAM available ∧ j=0 ⇒ 2 errors Exception Monad

module MonError where data E a = Error String | Ok a deriving Show instance Monad E where return x = Ok x m >>= f = case m of Error s -> Error s Ok x -> f x fail s = Error s printOut :: Show a => E a -> String printOut (Error s) = "Error: "++ s printOut (Ok x) = "Ok: " ++ show x Modelling State

• aim: providing operations for 1. specifying an initial state, 2. querying current state and 3. changing it • state transformer: function of type s → (a, s) mapping an initial state to a result value paired with the final state • data ST s a = ST (s → (a,s)) • once constructed, transformers of states of different type are obtained State Monad

module MonStateTrans where data ST s a = ST { unST::(s -> (a,s)) } instance Monad (ST s) where return x = ST (\s -> (x,s)) m >>= f = ST (\s -> let (x1,s1) = unST m s (x2,s2) = unST (f x1) s1 in (x2,s2)) fail x = error "lookup failed" printOut :: Show a => M a -> String printOut m = case unST m 0 of (a,s) -> "Count: " ++ show s ++ ", Value: " ++ show a Main Points:

• Why monads? neatly integrate side-effects into a pure functional language

• What is a monad? < M, return, <<= >

• How to use a monad? replace functions of type a → b by those of type a → M b Conclusion

benefits of monads: • introduce effects (e.g. state, concurrency, . . . ) and retain laziness and referential transparency • mix imperative + purely functional programming all laws of functional programming remain unconditionally valid • separation of concerns (values are distinguished from computations of values) • monadic style offers a new way of thinking about how to structure code • possibility of proving properties exploiting the monad laws More...

many other features with monads: • monad transformers allow the features of different monads to be combined • monadic parser combinators • additive monads (MonadPlus) • Reader/Writer monad • interface to code written in other languages • continuations • ... Further Reading

• Fundamentalist Functional Programming http://www.youtube.com/watch?v=UuamC0T3hv8 • PL book chapters 14-15 • A Gentle Introduction to Haskell 98 chapters 7,9 • The essence of functional programming by Phil Wadler http://homepages.inf.ed.ac.uk/wadler/papers/essence/essence.ps • Monads for functional programming by Phil Wadler http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf