Monads. A monad orders actions An action is any computation that has a natural notion of order. I.e. one thing happens before another. – IO is the action.

Slides:



Advertisements
Similar presentations
Introduction to Compilation of Functional Languages Wanhe Zhang Computing and Software Department McMaster University 16 th, March, 2004.
Advertisements

ML Datatypes.1 Standard ML Data types. ML Datatypes.2 Concrete Datatypes  The datatype declaration creates new types  These are concrete data types,
Kathleen Fisher cs242 Reading: “A history of Haskell: Being lazy with class”,A history of Haskell: Being lazy with class Section 6.4 and Section 7 “Monads.
CSE341: Programming Languages Lecture 16 Datatype-Style Programming With Lists or Structs Dan Grossman Winter 2013.
Functional Programming Universitatea Politehnica Bucuresti Adina Magda Florea
1 CS 161 Introduction to Programming and Problem Solving Chapter 9 C++ Program Components Herbert G. Mayer, PSU Status 10/20/2014.
Chapter 3 Simple Graphics. Side Effects and Haskell  All the programs we have seen so far have no “side-effects.” That is, programs are executed only.
Tim Sheard Oregon Graduate Institute Lecture 6: Monads and Interpreters CSE 510 Section FSC Winter 2004 Winter 2004.
Advanced Programming Handout 12 Higher-Order Types (SOE Chapter 18)
Cse536 Functional Programming 1 6/24/2015 Lecture #4, Oct 6, 2004 Reading Assignments –Begin Reading chapter 3 (Simple Graphics) of the Text Homework Assignment.
Comp 205: Comparative Programming Languages Functional Programming Languages: More Lists Recursive definitions List comprehensions Lecture notes, exercises,
CS510AP Quick Check Monads. QuickCheck Quick check is a Haskell library for doing random testing. You can read more about quickcheck at –
CSC 8310 Programming Languages Meeting 2 September 2/3, 2014.
Prof. Bodik CS 164 Lecture 51 Building a Parser I CS164 3:30-5:00 TT 10 Evans.
Miscellaneous Excel Combining Excel and Access. – Importing, exporting and linking Parsing and manipulating data. 1.
1 CSC 221: Introduction to Programming Fall 2012 Functions & Modules  standard modules: math, random  Python documentation, help  user-defined functions,
ML Datatypes.1 Standard ML Data types. ML Datatypes.2 Concrete Datatypes  The datatype declaration creates new types  These are concrete data types,
C++ Basics Structure of a Program. C++ Source Code Plain text file Typical file extension .CPP Must compile the C++ source code without errors before.
Comp150PLD Reading: “Tackling the Awkward Squad,” Sections 1-2Tackling the Awkward Squad “Real World Haskell,” Chapter 7: I/OReal World Haskell Thanks.
Advanced Functional Programming 2009 Ulf Norell (lecture by Jean-Philippe Bernardy)
1 C++ Syntax and Semantics, and the Program Development Process.
Interpretation Environments and Evaluation. CS 354 Spring Translation Stages Lexical analysis (scanning) Parsing –Recognizing –Building parse tree.
Chapter 2 Using Objects. Types A type defines a set of values and the operations that can be carried out on the values Examples: 13 has type int "Hello,
CS 536 Fall Scanner Construction  Given a single string, automata and regular expressions retuned a Boolean answer: a given string is/is not in.
Advanced Functional Programming Tim Sheard 1 Lecture 6 Functional Programming Tim Sheard & Mark Jones Monads & Interpreters.
A Second Look At ML 1. Outline Patterns Local variable definitions A sorting example 2.
© M. Winter COSC 4P41 – Functional Programming Programming with actions Why is I/O an issue? I/O is a kind of side-effect. Example: Suppose there.
Parsec Parsing. Parsec Parsec one of the standard libraries for building libraries. It is a combinator parser A parser parses a sequence of elements to.
0 Odds and Ends in Haskell: Folding, I/O, and Functors Adapted from material by Miran Lipovaca.
Arvind Computer Science and Artificial Intelligence Laboratory M.I.T. L13-1 October 26, 2006http:// Monadic Programming October.
Introduction to Loops Iteration Repetition Counting Loops Also known as.
Lee CSCE 314 TAMU 1 CSCE 314 Programming Languages Interactive Programs: I/O and Monads Dr. Hyunyoung Lee.
Introduction to Python Dr. José M. Reyes Álamo. 2 Three Rules of Programming Rule 1: Think before you program Rule 2: A program is a human-readable set.
First Order Haskell Neil Mitchell York University λ.
Chapter SevenModern Programming Languages1 A Second Look At ML.
CHAPTER 2 PROBLEM SOLVING USING C++ 1 C++ Programming PEG200/Saidatul Rahah.
Arrays.
Advanced Functional Programming Tim Sheard 1 Lecture 6 Advanced Functional Programming Tim Sheard Oregon Graduate Institute of Science & Technology Lecture.
Introduction to Computer Programming Concepts M. Uyguroğlu R. Uyguroğlu.
Software Engineering Algorithms, Compilers, & Lifecycle.
24-Jun-16 Haskell Dealing with impurity. Purity Haskell is a “pure” functional programming language Functions have no side effects Input/output is a side.
Advanced Functional Programming 2010
What is a Parser? A parser is a program that analyses a piece of text to determine its syntactic structure  3 means 23+4.
Arithmetic Expressions Function Calls Output
Theory of Computation Lecture 4: Programs and Computable Functions II
PROGRAMMING IN HASKELL
CS 4450: Principles of Programming Languages
CS 326 Programming Languages, Concepts and Implementation
CS4450: Principles of Programming Languages
Functions CIS 40 – Introduction to Programming in Python
Error Handling Summary of the next few pages: Error Handling Cursors.
PROGRAMMING IN HASKELL
CSE341: Programming Languages Lecture 16 Datatype-Style Programming With Lists or Structs Dan Grossman Spring 2017.
Arrays, For loop While loop Do while loop
Chapter 3: Lexical Analysis
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
Chapter 3: Input/Output
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
Functional Programming
CSE341: Programming Languages Lecture 16 Datatype-Style Programming With Lists or Structs Dan Grossman Spring 2016.
Programming Languages
Theory of Computation Lecture 4: Programs and Computable Functions II
PROGRAMMING IN HASKELL
Introduction to Computer Science
CSE341: Programming Languages Lecture 16 Datatype-Style Programming With Lists or Structs Dan Grossman Spring 2019.
Advanced Functional Programming
Presentation transcript:

Monads

A monad orders actions An action is any computation that has a natural notion of order. I.e. one thing happens before another. – IO is the action of altering the real world. – There are many other styles of computation that have a natural notion of order A Monad is Haskell’s way of specifying which actions come before others. The “do” operator provides this control over the order in which computations occur do { var <- location x -- the first action ; write var (b+1) -- the next action }

Observations Actions are first class. – They can be abstracted (parameters of functions) – Stored in data structures. -- It is possible to have a list of actions, etc. Actions can be composed. – They can be built out of smaller actions by glueing them together with do and return – They are sequenced with do much like one uses semi-colon in languages like Pascal and C. Actions can be performed (run). – separation of construction from performance is key to their versatility. Actions of type: Action() are like statements in imperative languages. – They are used only for their side effects.

Do syntactic sugar do { a; b } = do { _ <- a; b } do { x <- a ; do { y <- b ; do { z <- c ; d }}} = do {x <- a; y <- b; z <- c; d } = do x <- a y <- b z <- c d -- uses indentation -- rather than { ; }

Do: syntax, types, and order IO Int Int semi colons separate actions, good style to line ; up with opening { and closing } last action must must have type M a which is the type of do cannot have v <-... actions without v <-... must have type ( M a) for some monad M do { x <- f ; y <- g 7 ; putChar y ; return (x + 4) }

Monads have Axioms Order matters (and is maintained by Do ) – do { x <- do { y <- b; c } – ; d } = – do { y <- b; x <- c; d } Return introduces no effects – do { x <- Return a; e } = e[a/x] – do { x <- e; Return x } = e

Sample Monads data Id x = Id x data Exception x = Ok x | Fail data Env e x = Env (e -> x) data Store s x = Store (s -> (x,s)) data Mult x = Mult [x] data Output x = Output (x,String)

Sample Problem Importing Excel tables into Haskell (["1 die","2 die","3 die"],[("1",[Just 1,Nothing,Nothing]),("2",[Just 1,Just 1,Nothing]),("3",[Just 1,Just 2,Just 1]),("4",[Just 1,Just 3,Just 3]),("5",[Just 1,Just 4,Just 6]),("6",[Just 1,Just 5,Just 10]),("7",[Nothing,Just 6,Just 15]),("8",[Nothing,Just 5,Just 21]),("9",[Nothing,Just 4,Just 25]),("10",[Nothing,Just 3,Just 27]),("11",[Nothing,Just 2,Just 27]),("12",[Nothing,Just 1,Just 25]),("13",[Nothing,Nothing,Just 21]),("14",[Nothing,Nothing,Just 15]),("15",[Nothing,Nothing,Just 10]),("16",[Nothing,Nothing,Just 6]),("17",[Nothing,Nothing,Just 3]),("18",[Nothing,Nothing,Just 1])] )

Strategy Write Excel table into a comma separated values file. Use the CSV library to import the comma separated values file into Haskell as a [[String]] Process each sublist as a single line of the Excel table Interpret each string in the sublist as the correct form of data. E.g. an Int, or Bool, or list element, etc Note that order matters. The first element might be an Int, but the second might be a Bool.

[["","1 die„,"2 die","3 die"], ["1","1","",""], ["2","1","1",""], ["3","1","2","1"], ["4","1","3","3"], ["5","1","4","6"], ["6","1","5","10"], ["7","","6","15"], ["8","","5","21"], ["9","","4","25"], ["10","","3","27"], ["11","","2","27"], ["12","","1","25"], ["13","","","21"], ["14","","","15"], ["15","","","10"], ["16","","","6"], ["17","","","3"], ["18","","","1"],[""]] (["1 die","2 die","3 die"],[("1",[Just 1,Nothing,Nothing]),("2",[Just 1,Just 1,Nothing]),("3",[Just 1,Just 2,Just 1]),("4",[Just 1,Just 3,Just 3]),("5",[Just 1,Just 4,Just 6]),("6",[Just 1,Just 5,Just 10]),("7",[Nothing,Just 6,Just 15]),("8",[Nothing,Just 5,Just 21]),("9",[Nothing,Just 4,Just 25]),("10",[Nothing,Just 3,Just 27]),("11",[Nothing,Just 2,Just 27]),("12",[Nothing,Just 1,Just 25]),("13",[Nothing,Nothing,Just 21]),("14",[Nothing,Nothing,Just 15]),("15",[Nothing,Nothing,Just 10]),("16",[Nothing,Nothing,Just 6]),("17",[Nothing,Nothing,Just 3]),("18",[Nothing,Nothing,Just 1])] )

Pattern There is a pattern to the process Take a [String] as input Interpret 1 or more elements to produce data Return the data and the rest of the strings f:: [String] -> (Result,[String]) Repeat for the next piece of data Interpretation is different depending upon the data we want to produce.

What’s involved Lets observe what happens for the 6 th line of the Excel table 1.Read a string 2.Read 3 values to get a [Int] Note the order involved

Write some code getString:: [String] -> (String,[String]) getString (s:ss) = (s,ss) getString [] = error "No more strings to read a 'String' from" getInt:: [String] -> (Int,[String]) getInt (s:ss) = (read s,ss) getInt [] = error "No more strings to read an 'Int' from" Interpret as a string. I.e. do nothing Interpret as an Int. Use read

How can we get a list? getInts:: Int -> [String] -> ([Int],[String]) getInts 0 ss = ([],ss) getInts n ss = case getInt ss of (x,ss2) -> case getInts (n-1) ss2 of (xs,ss3) -> (x:xs,ss3) Note that the order is enforced by data dependencies, and we use the case to implement it.

Now get line 6 getLine6:: [String] -> ((String,[Int]),[String]) getLine6 ss = case getString ss of (count,ss2) -> case getInts 3 ss2 of (rolls,ss3) -> ((count,rolls),ss3) Note how the ordering is enforced again. We can do better than this

There are three patterns Threading of the list of strings in the function types – getString:: [String] -> (String,[String]) Threading in the use of the list (count,ss2) -> case getInts 3 ss2 of Use of the case to create data dependencies that enforce ordering This is a Monad

The State Monad import Control.Monad.State Defines the type constructor (State t a) – It behaves like – data State s a = State (s -> (a,s)) Use the do notation to compose and order actions (without performing them) Use the function evalState to perform actions

One of the standard libraries Use these functions, plus do and return to solve problems

Part of the code import Control.Monad.State type Line a = State [String] a type Reader a = State [[String]] a getLine6b :: Line (String,[Maybe Int]) getLine6b = do { count <- string ; rolls <- list 3 (blank int) ; return(count,rolls) }

The first line is different getLine1 :: Line [String] getLine1 = do { skip ; list 3 string }

What do int and string etc look like? int:: Line Int int = mapState f (return ()) where f ((),s:ss) = (read s,ss) f ((),[]) = error "No more strings to read an 'Int' from" list:: Int -> Line a -> Line [a] list 0 r = return [] list n r = do { x <- r; xs <- list (n-1) r; return(x:xs)} blank:: Line a -> Line(Maybe a) blank (State g) = State f where f ("":xs) = (Nothing, xs) f xs = case g xs of (y,ys) -> (Just y,ys)

From lines to files type Reader a = State [[String]] a lineToReader:: Line a -> Reader a lineToReader l1 = State g where g (line:lines) = (evalState l1 line, lines) getN :: Int -> Line a -> Reader [a] getN 0 line = return [] getN n line = do { x <- lineToReader line ; xs <- getN (n-1) line ; return(x:xs) }

Reading a whole file getFile :: Reader ([String],[(String,[Maybe Int])]) getFile = do { labels <- lineToReader getLine1 ; pairs <- getN 18 getLine6b ; return(labels,pairs) } importCSV :: Reader a -> String -> IO a importCSV reader file = do { r <- parseCSVFromFile file; (f r)} where f (Left err) = error ("Error reading from file: "++ file++"\n"++show err) f (Right xs) = return(evalState reader xs) test1 = importCSV getFile "roll3Die.csv"

Thoughts We use state monad at two different states – Lines where the state is [String] – Files where the state is [[String]] The use of the do notation makes the ordering explicit and is much cleaner than using nested case and threading (although this still happens) We have defined higher-order programs like list, blank, and lineToReader

Can we do better? Recall that monadic computations are first class. Can we capture patterns of use in our example to make things even simpler and more declarative. What patterns do we see again and again?

Patterns getFile = do { labels <- lineToReader getLine1 ; pairs <- getN 18 getLine6b ; return(labels,pairs) } getN n line = do { x <- lineToReader line ; xs <- getN (n-1) line ; return(x:xs) } getLine6b = do { count <- string ; rolls <- list 3 (blank int) ; return(count,rolls) } Run two computations in order and then combine the two results

Generic Monad Operations infixr 3 `x` x :: Monad m => m b -> m c -> m(b,c) r1 `x` r2 = do { a <- r1; b <- r2; return(a,b) } many :: Monad m => Int -> m c -> m [c] many n r = sequence (replicate n r) sequence [] = return [] sequence (c:cs) = do { x <- c; xs <- sequence cs; return(x:xs)}

Declarative description row:: (a -> b) -> Line a -> Reader b row f line1 = lineToReader line2 where line2 = do { x <- line1; return(f x) } get3DieEx2::Reader ([[Char]],[([Char],[Maybe Int])]) get3DieEx2 = (row snd (skip `x` list 3 string)) `x` (many 18 (row id cols2_18)) where cols2_18 = (string `x` list 3 (blank int))

What if we get it wrong? get3DieEx2 = (row snd (skip `x` list 3 string)) `x` (many 18 (row id cols2_18)) where cols2_18 = (string `x` list 4 (blank int)) Not very informative about where the error occurred

Thread more information in the state type Line a = State (Int,Int,[String]) a type Reader a = State (Int,[[String]]) a Where do we need to make changes? Remarkably, very few places Line and column information Line information

Only at the interface to the monad report l c message = error ("\n at line: "++show l++ ", column: "++show c++ "\n "++message) bool:: Line Bool bool = (State f) where f (l,c,"True" : ss) = (True,(l,c+1,ss)) f (l,c,"False" : ss) = (False,(l,c+1,ss)) f (l,c,x:xs) = report l c ("Non Bool in reader bool: "++x) f (l,c,[]) = report l c "No more strings to read a 'Bool' from"

string:: Line String string = State f where f (l,c,s:ss) = (s,(l,c+1,ss)) f (l,c,[]) = report l c "No more strings to read a 'String' from" int:: Line Int int = mapState f (return ()) where f ((),(l,c,s:ss)) = (read s,(l,c+1,ss)) f ((),(l,c,[])) = report l c "No more strings to read an 'Int' from" skip:: Line () skip = State f where f (l,c,s:ss) = ( (), (l,c+1,ss)) f (l,c,[]) = report l c "No more strings to 'skip' over" blank:: Line a -> Line(Maybe a) blank (State g) = State f where f (l,c,"":xs) = (Nothing, (l,c+1,xs)) f xs = case g xs of (y,ys) -> (Just y,ys)

Some thoughts lineToReader:: Line a -> Reader a lineToReader l1 = mapState f (return ()) where f ((),(l,line:lines)) = (evalState l1 (l,1,line),(l+1,lines)) Changes occur only where they matter Other functions use the same monadic interface The “plumbing” is handled automatically, even in the generic monad functions like `x` and `many`

We can see where the error occurred