Monads. COS 441 Slides 16

Similar documents
Software System Design and Implementation

Advanced Programming Handout 7. Monads and Friends (SOE Chapter 18)

CS 11 Haskell track: lecture 5. This week: State monads

Parsing. Zhenjiang Hu. May 31, June 7, June 14, All Right Reserved. National Institute of Informatics

Monads. Functional Programming (CS4011) Monads

CSCE 314 Programming Languages Functors, Applicatives, and Monads

Applicative, traversable, foldable

EECS 700 Functional Programming

Monads and all that I. Monads. John Hughes Chalmers University/Quviq AB

CS 457/557: Functional Languages

College Functors, Applicatives

Applicative, traversable, foldable

Monad class. Example: Lambda laughter. The functional IO problem. EDAN40: Functional Programming Functors and Monads

Introduction to Haskell

I/O in Haskell. To output a character: putchar :: Char -> IO () e.g., putchar c. To output a string: putstr :: String -> IO () e.g.

Haskell: From Basic to Advanced. Part 2 Type Classes, Laziness, IO, Modules

Monads seen so far: IO vs Gen

Introduction to Functional Programming in Haskell 1 / 56

Monad Overview (3B) Young Won Lim 1/16/18

IO Monad (3D) Young Won Lim 1/18/18

Programming Languages Fall 2013

Haske k ll An introduction to Functional functional programming using Haskell Purely Lazy Example: QuickSort in Java Example: QuickSort in Haskell

Monad Background (3A) Young Won Lim 10/5/17

An introduction introduction to functional functional programming programming using usin Haskell

n n Try tutorial on front page to get started! n spring13/ n Stack Overflow!

Standard prelude. Appendix A. A.1 Classes

Advanced Type System Features Tom Schrijvers. Leuven Haskell User Group

Background Type Classes (1B) Young Won Lim 6/28/18

Programming in Haskell Aug Nov 2015

State Monad (3D) Young Won Lim 8/31/17

CS The IO Monad. Slides from John Mitchell, K Fisher, and S. Peyton Jones

CS 320: Concepts of Programming Languages

Advanced Functional Programming

Haskell Introduction Lists Other Structures Data Structures. Haskell Introduction. Mark Snyder

Solution sheet 1. Introduction. Exercise 1 - Types of values. Exercise 2 - Constructors

Monad Background (3A) Young Won Lim 11/18/17

M-Structures (Continued)

IO Monad (3C) Young Won Lim 1/6/18

Programming Languages

10/21/08. Monads for functional programming uses! Kathleen Fisher!

Monads. Bonus lecture 2017 David Sands

Monads. Lecture 12. Prof. Aiken CS 264 Lecture 12 1

D7020E. The dynamic evolution of a system Robust and Energy-Efficient Real-Time Systems. blocked Lecture 2: Components & the Timber language.

D7020E. Robust and Energy-Efficient Real-Time Systems D7020E. Lecture 2: Components & the Timber language

State Monad (3D) Young Won Lim 9/25/17

Intro to Haskell Notes: Part 5

Functional Programming

CPL 2016, week 10. Clojure functional core. Oleg Batrashev. April 11, Institute of Computer Science, Tartu, Estonia

Monad Background (3A) Young Won Lim 11/8/17

CS 320: Concepts of Programming Languages

PROGRAMMING IN HASKELL. Chapter 10 - Interactive Programming

Functional Logic Programming Language Curry

CSCE 314 Programming Languages

IO Monad (3C) Young Won Lim 8/23/17

CS 11 Haskell track: lecture 1

These notes are intended exclusively for the personal usage of the students of CS352 at Cal Poly Pomona. Any other usage is prohibited without

CSCE 314 Programming Languages. Functional Parsers

CS 320 Homework One Due 2/5 11:59pm

GADTs. Wouter Swierstra and Alejandro Serrano. Advanced functional programming - Lecture 7. [Faculty of Science Information and Computing Sciences]

Background Type Classes (1B) Young Won Lim 6/14/18

CSC312 Principles of Programming Languages : Functional Programming Language. Copyright 2006 The McGraw-Hill Companies, Inc.

Interpreters. Prof. Clarkson Fall Today s music: Step by Step by New Kids on the Block

The List Datatype. CSc 372. Comparative Programming Languages. 6 : Haskell Lists. Department of Computer Science University of Arizona

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

The Substitution Model

Functional Programming and Haskell

GADTs. Alejandro Serrano. AFP Summer School. [Faculty of Science Information and Computing Sciences]

Haskell Types, Classes, and Functions, Currying, and Polymorphism

CS 11 Haskell track: lecture 4. n This week: Monads!

A general introduction to Functional Programming using Haskell

Haskell Refresher Informatics 2D

The Haskell HOP: Higher-order Programming

CS 135 Winter 2018 Tutorial 7: Accumulative Recursion and Binary Trees. CS 135 Winter 2018 Tutorial 7: Accumulative Recursion and Binary Trees 1

INTRODUCTION TO HASKELL

Programming with Math and Logic

Overview. Elements of Programming Languages. Evaluation order. Evaluation order

An introduction to functional programming. July 23, 2010

GADTs. Wouter Swierstra. Advanced functional programming - Lecture 7. Faculty of Science Information and Computing Sciences

OCaml Language Choices CMSC 330: Organization of Programming Languages

CS 209 Functional Programming

Haskell An Introduction

Haskell Monads CSC 131. Kim Bruce

Haskell & functional programming, some slightly more advanced stuff. Matteo Pradella

Quick announcement. Midterm date is Wednesday Oct 24, 11-12pm.

CS457/557 Functional Languages

Side Effects (3B) Young Won Lim 11/20/17

A Third Look At ML. Chapter Nine Modern Programming Languages, 2nd ed. 1

References. Monadic I/O in Haskell. Digression, continued. Digression: Creating stand-alone Haskell Programs

CS 440: Programming Languages and Translators, Spring 2019 Mon

Relation Overriding. Syntax and Semantics. Simple Semantic Domains. Operational Semantics

Side Effects (3B) Young Won Lim 11/23/17

Scheme: Data. CS F331 Programming Languages CSCE A331 Programming Language Concepts Lecture Slides Monday, April 3, Glenn G.

The Worker/Wrapper Transformation

Programming in Haskell Aug-Nov 2015

Informatics 1 Functional Programming 19 Tuesday 23 November IO and Monads. Philip Wadler University of Edinburgh

CSCE 314 Programming Languages

CSCE 314 Programming Languages. Interactive Programming: I/O

Side Effects (3B) Young Won Lim 11/27/17

QuickCheck, SmallCheck & Reach: Automated Testing in Haskell. Tom Shackell

Set Haskell Exercises

Transcription:

Monads COS 441 Slides 16

Last time: Agenda We looked at implementation strategies for languages with errors, with printing and with storage We introduced the concept of a monad, which involves 3 things: What is the type of the result of evaluation? ie: what type defines the monad type class instance How do we evaluate a pure value and do nothing else? ie: how do we implement return How do we compose evaluation of two subexpressions ie: how do we implement bind : e >>= f This time: How do we implement monads for printing and for storage? Can we use monads more generally?

REVIEW: THE ERROR MONAD

The Monad Typeclass the type class Monad m where return :: a -> m a -- the null computation (>>=) :: m a -> (a -> m b) -> m b -- bind ie: composition A useful derived operator: >> :: m a -> m b -> m b -- sequencing x >> y = (x >>= f) where f _ = y

The error monad: The Error Monad instance Monad Maybe where return v = Just v -- an error-free computation that -- does nothing but return a value v -- (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b (Just v) >>= f = f v -- compose an error-free computation with f Nothing >>= f = Nothing -- compose an error-full computation with f

The error monad: The Error Monad instance Monad Maybe where return v = Just v -- an error-free computation that -- does nothing but return a value v -- (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b (Just v) >>= f = f v -- compose an error-free computation with f Nothing >>= f = Nothing -- compose an error-full computation with f Using the error monad: eval (Val v) = return v do block eval (Add e1 e2) = do x <- eval e1 y <- eval e2 return (x + y)

The error monad: The Error Monad instance Monad Maybe where return v = Just v -- an error-free computation that -- does nothing but return a value v -- (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b (Just v) >>= f = f v -- compose an error-free computation with f Nothing >>= f = Nothing -- compose an error-full computation with f Using the error monad: eval (Val v) = return v do block eval (Add e1 e2) = do x <- eval e1 y <- eval e2 return (x + y) eval (Add e1 e2) = eval e1 >>= (\x. eval e1 >>= (\y. return (x + y)))

THE PRINTING MONAD

Recall Evaluation of Printing Expressions data Expr3= Val3 Int Add3 Expr3 Expr3 PrintThen String Expr3 eval3 :: Expr3 -> (String, Int) eval3 (Val3 x) = ("", x) null computation eval3 (Add3 e1 e2) = let (s1,n1) = eval3 e1 (s2,n2) = eval3 e2 in (s1 ++ s2, n1 + n2) eval3 (PrintThen s e) = let (s', n) = eval3 e in (s ++ s', n) plumbing that arises from composing computations that manipulate strings

Recall Evaluation of Printing Expressions data Expr3= Val3 Int Add3 Expr3 Expr3 PrintThen String Expr3 instance Monad (String, a) where eval3 :: Expr3 -> (String, Int) eval3 (Val2 x) = ("", x) eval3 (Add3 e1 e2) = let (s1,n1) = eval3 e1 (s2,n2) = eval3 e2 in (s1 ++ s2, n1 + n2) eval3 (PrintThen s e) = let (s', n) = eval3 e in (s ++ s', n) intuitively, we would like to make a monad from just a pair of a String and a return value a however, we can only attach type classes to abstract types created using the data or newtype keywords

Recall Evaluation of Printing Expressions data Expr3= Val3 Int Add3 Expr3 Expr3 PrintThen String Expr3 newtype Output a = Out (String, a) instance Monad Output where eval3 :: Expr3 -> (String, Int) eval3 (Val2 x) = ("", x) eval3 (Add3 e1 e2) = let (s1,n1) = eval3 e1 (s2,n2) = eval3 e2 in (s1 ++ s2, n1 + n2) eval3 (PrintThen s e) = let (s', n) = eval3 e in (s ++ s', n)

Recall Evaluation of Printing Expressions data Expr3= Val3 Int Add3 Expr3 Expr3 PrintThen String Expr3 eval3 :: Expr3 -> (String, Int) eval3 (Val2 x) = ("", x) eval3 (Add3 e1 e2) = let (s1,n1) = eval3 e1 (s2,n2) = eval3 e2 in (s1 ++ s2, n1 + n2) eval3 (PrintThen s e) = let (s', n) = eval3 e in (s ++ s', n) newtype Output a = Out (String, a) instance Monad Output where return v = Out ("", v) (Out (s,v)) >>= f = let (s',v') = f v in (s ++ s', v')

Recall Evaluation of Printing Expressions data Expr3= Val3 Int Add3 Expr3 Expr3 PrintThen String Expr3 eval3 :: Expr3 -> (String, Int) eval3 (Val2 x) = ("", x) eval3 (Add3 e1 e2) = let (s1,n1) = eval3 e1 (s2,n2) = eval3 e2 in (s1 ++ s2, n1 + n2) eval3 (PrintThen s e) = let (s', n) = eval3 e in (s ++ s', n) newtype Output a = Out (String, a) instance Monad Output where return v = Out ("", v) (Out (s,v)) >>= f = let (s',v') = f v in (s ++ s', v') printme s = Out (s, ())

Recall Evaluation of Printing Expressions data Expr3= Val3 Int Add3 Expr3 Expr3 PrintThen String Expr3 eval3 :: Expr3 -> (String, Int) eval3 (Val2 x) = ("", x) eval3 (Add3 e1 e2) = let (s1,n1) = eval3 e1 (s2,n2) = eval3 e2 in (s1 ++ s2, n1 + n2) eval3 (PrintThen s e) = let (s', n) = eval3 e in (s ++ s', n) newtype Output a = Out (String, a) instance Monad Output where return v = Out ("", v) (Out (s,v)) >>= f = let (s',v') = f v in (s ++ s', v') printme s = Out (s, ()) eval3 (Val3 x) = return x eval3 (Add3 e1 e2) = do n1 <- eval3 e1 n2 <- eval3 e2 return (n1 + n2) eval3 (PrintThen s e) = do printme s eval3 e

Comparing Implementations of add eval :: Expr1 -> Maybe Int eval (Val1 x) = return x eval (Add1 e1 e2) = do n1 <- eval e1 n2 <- eval e2 return (n1 + n2) eval3 :: Expr3 -> Output Int eval3 (Val3 x) = return x eval3 (Add3 e1 e2) = do n1 <- eval3 e1 n2 <- eval3 e2 return (n1 + n2) The only difference is the type, which controls which monad we are evaluating inside of, using the type class mechanism We have isolated the essence of evaluating addition, independently of other side-effects such as errors or printing! This is deep! What an abstraction!

THE STATE MONAD

Recall Evaluation of a Stateful Language data Expr4 = Val4 Add4 Expr4 Expr4 StoreThen Expr4 Expr4 Read type State = Int type Result a = State -> (State, a) eval4 :: Expr4 -> Result a eval4 (Val4 x) = \s -> (s, x) implementing reading and writing requires a state transformer eval4(read) = \s -> (s, s) eval4(add e1 e2) = let f1 = eval4 e1 f2 = eval4 e2 in \s0 -> let (s1, n1) = f1 s0 (s2, n2) = f2 s1 in (s2, n1 + n2) eval4 (StoreThen e1 e2) = let f1 = eval4 e1 f2 = eval4 e2 in \s0 -> let (_, n1) = f1 s0 in f2 n1

The State Monad type State = Int newtype SM a = Transform (State -> (State, a)) instance Monad (SM) where

The State Monad type State = Int newtype SM a = Transform (State -> (State, a)) instance Monad (SM) where return x = -- return :: a -> SM a

The State Monad type State = Int newtype SM a = Transform (State -> (State, a)) instance Monad (SM) where return x = Transform (\s -> (s,x)) -- return :: a -> SM a

The State Monad type State = Int newtype SM a = Transform (State -> (State, a)) instance Monad (SM) where return x = Transform (\s -> (s,x)) (Transform t) >>= f = -- return :: a -> SM a -- (>>=) :: SM a -> (a -> SM b) -> SM b -- t :: State -> (State, a), f :: a -> SM b

The State Monad type State = Int newtype SM a = Transform (State -> (State, a)) instance Monad (SM) where return x = Transform (\s -> (s,x)) (Transform t) >>= f = Transform (\s ->... -- return :: a -> SM a -- (>>=) :: SM a -> (a -> SM b) -> SM b -- t :: State -> (State, a), f :: a -> SM b -- s :: State

The State Monad type State = Int newtype SM a = Transform (State -> (State, a)) instance Monad (SM) where return x = Transform (\s -> (s,x)) -- return :: a -> SM a (Transform t) >>= f = -- (>>=) :: SM a -> (a -> SM b) -> SM b Transform -- t :: State -> (State, a), f :: a -> SM b (\s -> -- s :: State let (s', x) = t s in -- x :: a let (Transform g) = f x in -- g :: State -> (State, b) g s')

The State Monad type State = Int newtype SM a = Transform (State -> (State, a)) instance Monad (SM) where return x = Transform (\s -> (s,x)) -- return :: a -> SM a (Transform t) >>= f = -- (>>=) :: SM a -> (a -> SM b) -> SM b Transform -- t :: State -> (State, a), f :: a -> SM b (\s -> -- s :: State let (s', x) = t s in -- x :: a let (Transform g) = f x in -- g :: State -> (State, b) g s') getstate :: SM State getstate = Transform (\s -> (s, s)) setstate :: State -> SM () setstate s' = Transform (\s -> (s', ()))

The State Monad type State = Int newtype SM a = Transform (State -> (State, a)) instance monad (SM) where return x = Transform (\s -> (s,x)) eval4 (Val4 x) = return x eval4 (Read) =... (Transform t) >>= f = Transform (\s -> let (s', x) = t s in let (Transform g) = f x in g s') getstate :: SM State getstate = Transform (\s -> (s, s)) setstate :: State -> SM () setstate s' = Transform (\s -> (s', ()))

The State Monad type State = Int newtype SM a = Transform (State -> (State, a)) instance monad (SM) where return x = Transform (\s -> (s,x)) eval4 (Val4 x) = return x eval4 (Read) = getstate (Transform t) >>= f = Transform (\s -> let (s', x) = t s in let (Transform g) = f x in g s') getstate :: SM State getstate = Transform (\s -> (s, s)) setstate :: State -> SM () setstate s' = Transform (\s -> (s', ()))

The State Monad type State = Int newtype SM a = Transform (State -> (State, a)) instance monad (SM) where return x = Transform (\s -> (s,x)) (Transform t) >>= f = Transform (\s -> let (s', x) = t s in let (Transform g) = f x in g s') eval4 (Val4 x) = return x eval4 (Read) = getstate eval4 (Add e1 e2) = n1 <- eval4 e1 n2 <- eval4 e2 return (n1 + n2) eval4 (StoreThen e1 e2) =... getstate :: SM State getstate = Transform (\s -> (s, s)) setstate :: State -> SM () setstate s' = Transform (\s -> (s', ()))

The State Monad type State = Int newtype SM a = Transform (State -> (State, a)) instance monad (SM) where return x = Transform (\s -> (s,x)) (Transform t) >>= f = Transform (\s -> let (s', x) = t s in let (Transform g) = f x in g s') getstate :: SM State getstate = Transform (\s -> (s, s)) eval4 (Val4 x) = return x eval4 (Read) = getstate eval4 (Add e1 e2) = n1 <- eval4 e1 n2 <- eval4 e2 return (n1 + n2) eval4 (StoreThen e1 e2) = n1 <- eval4 e1 setstate n1 eval e2 setstate :: State -> SM () setstate s' = Transform (\s -> (s', ()))

The State Makeover: Before and After Before the state monad: eval4 (Val4 x) = \s -> (s, x) eval4(read) = \s -> (s, s) eval4(add e1 e2) = let f1 = eval4 e1 f2 = eval4 e2 in \s0 -> let (s1, n1) = f1 s0 (s2, n2) = f2 s1 in (s2, n1 + n2) eval4 (StoreThen e1 e2) = let f1 = eval4 e1 f2 = eval4 e2 in \s0 -> let (_, n1) = f1 s0 in f2 n1 After the state monad: eval4 (Val4 x) = return x eval4 (Read) = getstate eval4 (Add e1 e2) = n1 <- eval4 e1 n2 <- eval4 e2 return n1 + n2 eval4 (StoreThen e1 e2) = n1 <- eval4 e1 setstate n1 eval e2

USING MONADS IN GENERAL-PURPOSE COMPUTATIONS

Why Did Haskell Implementers Bother? Did the Haskell implementers really invent monads and a special syntax just to make it easier to implement expression evaluators? No! Of course not. Monads are used more generally to compose computations

Why Did Haskell Implementers Bother? "Walker, David, Prof" "Monsanto, Chris, TA" inputs "Kid, Wiz, Student" "Wiz, Not" ""

Why Did Haskell Implementers Bother? inputs "Walker, David, Prof" "Monsanto, Chris, TA" "Kid, Wiz, Student" "Wiz, Not" "" Consider a simple string processing application: csvconvert s = aux "" s where aux "" [] = [] aux s [] = [reverse s] aux s (',' : cs) = reverse s : aux "" cs aux s (c : cs) = aux (c:s) cs By the way, what is the type of csvconvert?

Why Did Haskell Implementers Bother? inputs "Walker, David, Prof" "Monsanto, Chris, TA" "Kid, Wiz, Student" "Wiz, Not" "" Consider a simple string processing application: csvconvert s = aux "" s where aux "" [] = [] aux s [] = [reverse s] aux s (',' : cs) = reverse s : aux "" cs aux s (c : cs) = aux (c:s) cs Add a list indexing function: index :: [a] -> Int -> Maybe a index [] i = Nothing index (x:xs) 0 = Just x index (x:xs) i = index xs (i-1)

Why Did Haskell Implementers Bother? inputs "Walker, David, Prof" "Monsanto, Chris, TA" "Kid, Wiz, Student" "Wiz, Not" "" csvconvert :: String -> [String] index :: [a] -> Int -> Maybe a getall :: String -> Maybe (String, String, String) getall s =

Why Did Haskell Implementers Bother? inputs "Walker, David, Prof" "Monsanto, Chris, TA" "Kid, Wiz, Student" "Wiz, Not" "" red is useful computation blue is plumbing so much plumbing!!! plumbing just like the plumbing in our evaluator! csvconvert :: String -> [String] index :: [a] -> Int -> Maybe a getall :: String -> Maybe (String, String, String) getall s = let items = csvconvert s in case index items 0 of Nothing -> Nothing Just last -> case index items 1 of Nothing -> Nothing Just first -> case index items 2 of Nothing -> Nothing Just role -> Just (last, first, role)

Why Did Haskell Implementers Bother? inputs "Walker, David, Prof" "Monsanto, Chris, TA" "Kid, Wiz, Student" "Wiz, Not" "" csvconvert :: String -> [String] index :: [a] -> Int -> Maybe a getall :: String -> Maybe (String, String, String) getall s = do let items = csvconvert s last <- index items 0 first <- index items 1 role <- index items 2 return (first, last, role) the Maybe monad takes care of the error-propagation plumbing!

Programming with Errors In general, we might have a whole bunch of functions that can produce errors: gethead :: [a] -> Maybe a gettail :: [a] -> Maybe [a] getstart :: [a] -> Maybe [a] getlast :: [a] -> Maybe a We can string them together inside a monad that does errorpropagation for us : exchange :: [a] -> Maybe [a] exchange xs =do x <- gethead xs ys <- gettail xs zs <- getstart ys z <- getlast ys return (z ++ zs ++ x)

PROGRAMMING WITH STATE IN HASKELL

Programming with State In Java, a unique string generator: global variable static int n = 0; no parameters String gen () { String s = "x" + Integer.toString(n); n = n + 1; return s; } An analogous functional Haskell program: global variable becomes parameter and result gen :: Int -> (String, Int) gen n = ("x" ++ show n, n + 1)

In functional languages, you have to manually thread the state through the program. Yuck! No wonder no one uses them! Using State In Java (or C or most other imperative languages): String s1, s2, s3; s1 = gen() s2 = gen() s3 = gen() In Haskell: let n0 = 0 in let (s1, n1) = gen n0 in let (s2, n2) = gen n1 in let (s3, n3) = gen n3 in. plumbing!

A Generic State Monad data ST s a = S (s -> (a, s)) apply :: ST s a -> s -> (a, s) apply (S f) x = f x

A Generic State Monad data ST s a = S (s -> (a, s)) apply :: ST s a -> s -> (a, s) apply (S f) x = f x instance Monad (ST s) where return x = S (\s -> (x,s)) -- type State = ST s -- return :: a -> State a st >>= f = S transform -- (>>=) :: State a -> (a -> State b) -> State b where transform s = let (x,s') = apply st s in apply (f x) s'

Using the State Monad data Tree a = Leaf a Node (Tree a) (Tree a) tree :: Tree Char tree = Node (Node (Leaf 'a') (Leaf 'b')) (Leaf 'c') type State = ST Int -- Int is the kind of state we'll use gen :: State String gen = S (\n -> ("x" ++ show n, n+1)) treelabel :: Tree a -> State (Tree (String, a))

Using the State Monad data Tree a = Leaf a Node (Tree a) (Tree a) tree :: Tree Char tree = Node (Node (Leaf 'a') (Leaf 'b')) (Leaf 'c') type State = ST Int -- Int is the kind of state we'll use gen :: State String gen = S (\n -> ("x" ++ show n, n+1)) treelabel :: Tree a -> State (Tree (String, a)) treelabel (Leaf x) = do s <- gen return (Leaf (s, x)) treelabel (Node l r) = do l' <- mlabel l r' <- mlabel r return (Node l' r')

Using the State Monad data Tree a = Leaf a Node (Tree a) (Tree a) tree :: Tree Char tree = Node (Node (Leaf 'a') (Leaf 'b')) (Leaf 'c') type State = ST Int -- Int is the kind of state we'll use gen :: State String gen = S (\n -> ("x" ++ show n, n+1)) treelabel :: Tree a -> State (Tree (String, a)) treelabel (Leaf x) = do s <- gen return (Leaf (s, x)) treelabel (Node l r) = do l' <- mlabel l r' <- mlabel r return (Node l' r') runst :: State a -> a runst s = fst (apply s 0) treelab :: Tree a -> Tree (String, a) treelab t = runst (treelabel t)

BUILT-IN STATE

IO Monad Haskell uses monads itself to structure its own evaluation: main :: IO Char main = do putstr Hello c <- getchar putstr IO is a complex monad combining: printing to standard out reading files writing files reading command-line args writing mutable references (state) reading mutable references errors exceptions all of the "effects" you find in ordinary languages

IO Monad Intuitively: data ST s a = S (s -> (a, s)) type World = newtype IO a = ST World a Using the IO monad allows us to modify the "world" files stdout

import Data.IORef as R Built-in Mutable References new = R.newIORef -- create a new mutable object with 1 field get = R.readIORef -- read out the stored object r!= n = R.writeIORef r n -- store n into reference r

import Data.IORef as R Built-in Mutable References new = R.newIORef -- create a new mutable object with 1 field get = R.readIORef -- read out the stored object r!= n = R.writeIORef r n -- store n into reference r mkgenerator :: IO (IO String) mkgenerator = do r <- new 0 let gen = do n <- get r r!= (n+1) return ("x" ++ show n)) return gen

Built-in Mutable References mkgenerator = do r <- new 0 let gen = do n <- get r r!= (n+1) return ("x" ++ show n)) return gen mynames = do gen <- mkgenerator x1 <- gen y1 <- gen gen' <- mkgenerator x2 <- gen' y2 <- gen' z1 <- gen return ([x1,y1,z1], [x2,y2]) in ghci: *Main> mynames (["x0","x1","x2"],["x0","x1"])

Mutable Data Structures A pure, functional binary search tree (not mutable): BST key val = Null Node key val (Tree a) (Tree a) A tree with mutable leaves: import Data.IORef MBST key val = Null Node key (IORef val) (Tree a) (Tree a) single key val = do r <- new v return (Node k r Null Null)

Mutable Data Structures A pure, functional binary search tree (not mutable): BST key val = Null Node key val (Tree a) (Tree a) A tree with mutable leaves: import Data.IORef MBST key val = Null Node key (IORef val) (Tree a) (Tree a) update :: (Ord key) => MBST key val -> key -> val -> IO Bool update Null k v = return False update (Node k' r' left right) k v = if k' == k then do {r'!= v; return True} else if k' < k then update left k v else update right k v return true if update succeeds return false if not

Get me out of here! When we built our own state monad, we could extract the final value and throw away the state: runst :: State a -> a runst s = fst (apply s 0) When we work within the state monad, we can't do that. There is no safe function: performio :: IO a -> a But you can use unsafe IO: import System.IO.Unsafe unsafeperformio :: IO a -> a See: http://www.haskell.org/ghc/docs/latest/html/libraries/base/system-io-unsafe.html

SUMMARY

We learned several things: Summary We can simplify the implementation of evaluators by using monads We can simplify implementation and composition of more general computations using monads errors using maybe string creation (ie "printing") state Haskell has some built-in monads for handling effects, the most common being the IO monad The latter is at the core of how Haskell handles effects and yet still acts like a functional program and preserves powerful reasoning principles involving substitution of equals for equals