Introducing Monads Lecture 3, Designing and Using Combinators John Hughes.

Slides:



Advertisements
Similar presentations
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.
Advertisements

8. Introduction to Denotational Semantics. © O. Nierstrasz PS — Denotational Semantics 8.2 Roadmap Overview:  Syntax and Semantics  Semantics of Expressions.
Annoucements  Next labs 9 and 10 are paired for everyone. So don’t miss the lab.  There is a review session for the quiz on Monday, November 4, at 8:00.
© M. Winter COSC 4P41 – Functional Programming Abstract data types (ADTs) An ADT is a data type together with some functions to manipulate elements.
Domain Specific Embedded Languages Lecture 2, Designing and Using Combinators John Hughes.
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.
Week 9: Methods 1.  We have written lots of code so far  It has all been inside of the main() method  What about a big program?  The main() method.
CSE341: Programming Languages Lecture 8 Lexical Scope and Function Closures Dan Grossman Fall 2011.
Lecture 27 Exam outline Boxing of primitive types in Java 1.5 Generic types in Java 1.5.
CS 206 Introduction to Computer Science II 01 / 21 / 2009 Instructor: Michael Eckmann.
A Lightning Tour of Haskell Lecture 1, Designing and Using Combinators John Hughes.
Advanced Programming Handout 12 Higher-Order Types (SOE Chapter 18)
Cse536 Functional Programming 1 6/23/2015 Lecture #17, Dec. 1, 2004 Todays Topics – Higher Order types »Type constructors that take types as arguments.
Two Case Studies: QuickCheck and Wash/CGI Lecture 4, Designing and Using Combinators John Hughes.
Generic Subroutines and Exceptions CS351 – Programming Paradigms.
CS510AP Quick Check Monads. QuickCheck Quick check is a Haskell library for doing random testing. You can read more about quickcheck at –
C++ Functions. 2 Agenda What is a function? What is a function? Types of C++ functions: Types of C++ functions: Standard functions Standard functions.
Monads Technion – Institute of Technology Software Design (236700) Author: Gal Lalouche - Technion 2015 © 1.
And other languages…. must remember to check return value OR, must pass label/exception handler to every function Caller Function return status Caller.
CS 11 C track: lecture 5 Last week: pointers This week: Pointer arithmetic Arrays and pointers Dynamic memory allocation The stack and the heap.
Top-Down Parsing - recursive descent - predictive parsing
Introduction to Parsing Copyright 2003, Keith D. Cooper, Ken Kennedy & Linda Torczon, all rights reserved. Students enrolled in Comp 412 at Rice University.
Deriving Combinator Implementations Lecture 4, Designing and Using Combinators John Hughes.
Functional Programming and Lisp. Overview In a functional programming language, functions are first class objects. In a functional programming language,
Advanced Functional Programming 2009 Ulf Norell (lecture by Jean-Philippe Bernardy)
Course: Software Engineering ©Alessandra RussoUnit 2: States and Operations, slide number 1 States and Operations This unit aims to:  Define: State schemas.
Hey, Ferb, I know what we’re gonna do today! Aims: Use formatted printing. Use the “while” loop. Understand functions. Objectives: All: Understand and.
1 BUILDING JAVA PROGRAMS CHAPTER 6 FILE PROCESSING.
Advanced Functional Programming Tim Sheard 1 Lecture 6 Functional Programming Tim Sheard & Mark Jones Monads & Interpreters.
Topics: Function Intitution Algorithm Example Function Definition (and Indentation) Function Call Naming and Binding Local Variables Function Arguments.
© 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.
Arvind Computer Science and Artificial Intelligence Laboratory M.I.T. L13-1 October 26, 2006http:// Monadic Programming October.
A Monadic-Memoized Solution for Left-Recursion Problem of Combinatory Parser Rahmatullah Hafiz Fall, 2005.
Lee CSCE 314 TAMU 1 CSCE 314 Programming Languages Interactive Programs: I/O and Monads Dr. Hyunyoung Lee.
Basic Scheme February 8, 2007 Compound expressions Rules of evaluation Creating procedures by capturing common patterns.
CSE 332: C++ Statements C++ Statements In C++ statements are basic units of execution –Each ends with ; (can use expressions to compute values) –Statements.
What am I? while b != 0 if a > b a := a − b else b := b − a return a AST == Abstract Syntax Tree.
First Order Haskell Neil Mitchell York University λ.
ICS3U_FileIO.ppt File Input/Output (I/O)‏ ICS3U_FileIO.ppt File I/O Declare a file object File myFile = new File("billy.txt"); a file object whose name.
Written by: Dr. JJ Shepherd
Lecture 04: Theory of Automata:08 Transition Graphs.
COMP 3438 – Part II-Lecture 5 Syntax Analysis II Dr. Zili Shao Department of Computing The Hong Kong Polytechnic Univ.
Advanced Functional Programming Tim Sheard 1 Lecture 6 Advanced Functional Programming Tim Sheard Oregon Graduate Institute of Science & Technology Lecture.
(c) University of Washington10-1 CSC 143 Java Errors and Exceptions Reading: Ch. 15.
CSE 341 : Programming Languages Lecture 9 Lexical Scope, Closures Zach Tatlock Spring 2014.
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.
CSE 332: C++ Exceptions Motivation for C++ Exceptions Void Number:: operator/= (const double denom) { if (denom == 0.0) { // what to do here? } m_value.
Advanced Functional Programming 2010
Announcements Today: the Parsing Domain-specific Language
Basic Scheme February 8, 2007 Compound expressions Rules of evaluation
COMP261 Lecture 18 Parsing 3 of 4.
CS 4450: Principles of Programming Languages
Material in the textbook on pages
AFP - Lecture 2 Domain Specific Embedded Languages
Lecture 2 Domain Specific Embedded Languages
PROGRAMMING IN HASKELL
Learning to Program in Python
CSE341: Programming Languages Lecture 8 Lexical Scope and Function Closures Dan Grossman Winter 2013.
CSE341: Programming Languages Lecture 8 Lexical Scope and Function Closures Dan Grossman Spring 2013.
Lecture 7: Introduction to Parsing (Syntax Analysis)
CSE341: Programming Languages Lecture 8 Lexical Scope and Function Closures Dan Grossman Spring 2016.
PROGRAMMING IN HASKELL
CSE341: Programming Languages Lecture 8 Lexical Scope and Function Closures Dan Grossman Autumn 2018.
CSE341: Programming Languages Lecture 8 Lexical Scope and Function Closures Zach Tatlock Winter 2018.
CSCE 314: Programming Languages Dr. Dylan Shell
Programming Languages
CSE341: Programming Languages Lecture 8 Lexical Scope and Function Closures Dan Grossman Autumn 2017.
CSE341: Programming Languages Lecture 8 Lexical Scope and Function Closures Dan Grossman Spring 2019.
Advanced Functional Programming
Presentation transcript:

Introducing Monads Lecture 3, Designing and Using Combinators John Hughes

Common ”Look and Feel” We have already seen that do and return can be used with many different DSELs: Parsers, Wash/CGI IO, ST s These are all examples of monads. A monad is something that supports do and return!

The do Syntactic Sugar The do syntax is just sugar for using an overloaded operator: do x <- e c e >>= (\x -> do c) do ee Sequencing. Common in DSLs. ”bind”

Example do s <- readFile f writeFile g s return s readFile f >>= \s-> writeFile g s >>= \_-> return s

What are the Types? A monad is always associated with a parameterised type, e.g. IO or ST s, the type of actions. readFile f >>= \s-> writeFile g s >>= \_-> return s Call it m. return :: a -> m a What is the type of >>=?

What are the Types? A monad is always associated with a parameterised type, e.g. IO or ST s, the type of actions. readFile f >>= \s-> writeFile g s >>= \_-> return s Call it m. return :: a -> m a What is the type of >>=? (>>=) :: m a -> … -> … First arg is an action

What are the Types? A monad is always associated with a parameterised type, e.g. IO or ST s, the type of actions. readFile f >>= \s-> writeFile g s >>= \_-> return s Call it m. return :: a -> m a What is the type of >>=? (>>=) :: m a -> (a -> …) -> … Second arg receives result of first

What are the Types? A monad is always associated with a parameterised type, e.g. IO or ST s, the type of actions. readFile f >>= \s-> writeFile g s >>= \_-> return s Call it m. return :: a -> m a What is the type of >>=? (>>=) :: m a -> (a -> m b) -> … Second arg returns an action

What are the Types? A monad is always associated with a parameterised type, e.g. IO or ST s, the type of actions. readFile f >>= \s-> writeFile g s >>= \_-> return s Call it m. return :: a -> m a What is the type of >>=? (>>=) :: m a -> (a -> m b) -> m b Result is an action returning result of second arg.

The Monad Class Monad operations are overloaded (hence can be used with many libraries). class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b instance Monad IO … instance Monad (ST s) …

The Monad Class Monad operations are overloaded (hence can be used with many libraries). class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b instance Monad Parser … instance Monad CGI …

Why Use Monads?

A shared interface to many libraries allows a common ”look and feel” -- familiarity! allows shared code functionality the DSEL implementor need not implement … and which users already know how to use. liftM :: Monad m => (a->b) -> m a -> m b sequence :: Monad m => [m a] -> m [a] do syntactic sugar! Standard library Monad

Why Use Monads? A shared interface to many libraries A design guideline: no need to spend intellectual effort on the design of sequencing operations.

Why Use Monads? A shared interface to many libraries A design guideline: no need to spend intellectual effort on the design of sequencing operations. A systematic implementation: saves intellectual effort, encourages code reuse.

Systematic Monad Implementation Start with an underlying monad (e.g. IO, ST) Add features (e.g. state, exceptions, concurrency) one by one.

Systematic Monad Implementation Start with an underlying monad (e.g. IO, ST) Add features (e.g. state, exceptions, concurrency) one by one. This can be automated!

The Identity Monad The ”vanilla” monad, supporting no special features. newtype Id a = Id a instance Monad Id where return x = Id x Id x >>= f = f x An abstract type: represented by an a, but a different type. Note (in passing) that >>= is lazy -- it doesn’t need its first argument unless f does. Monadic ”sequencing” doesn’t imply sequencing in time…

Adding Features: Monad Transformers A monad transformer transforms an existing monad (without a particular feature) into a new monad which has it. A parameterised monad -- represent by a parameterised type! What should the method(s) be? class (Monad m, Monad (t m)) => MonadTransformer t m where …

Adding Features: Monad Transformers A monad transformer transforms an existing monad (without a particular feature) into a new monad which has it. A parameterised monad -- represent by a parameterised type! Anything we can do in the old monad, we can also do in the new… class (Monad m, Monad (t m)) => MonadTransformer t m where lift :: m a -> t m a

Example: Adding State Consider adding a state feature: actions may depend on, and change, a state. class Monad m => StateMonad s m | m -> s where update :: (s -> s) -> m s readState = update id writeState s = update (\_->s) tick :: StateMonad Integer m => m Integer tick = do n <- readState writeState (n+1) return n

The State Monad How can we add a state to actions? Let actions take the state as an argument, and deliver a new state as a result. newtype State s m a = State (s -> m (s,a)) Parameterised on both the state and the underlying monad.

The State Monad The monad operations just pass the state along. newtype State s m a = State (s -> m (s,a)) instance Monad m => Monad (State s m) where return x = State $ \s -> return (s,x) State f >>= h = State $ \s -> do (s’,a) <- f s let State g = h a g s’

The State Monad is a StateMonad newtype State s m a = State (s -> m (s,a)) Of course, we can implement update: instance Monad m => StateMonad s (State s m) where update f = State $ \s -> let s’ = f s in return (s’,s’)

State is a Monad Transformer Can we ”lift” actions in the underlying monad? Yes -- they don’t change the state! newtype State s m a = State (s -> m (s,a)) instance MonadTransformer (State s) m where lift a = State $ \s -> do x <- a return (s,x)

Last Step: Run Functions We must be able to observe the result of an action -- otherwise the action is useless! (The only exception is the IO monad, which is observable at the top level). We define a run function for every monad (c.f. runST). runId (Id a) = s runState s (State f) = let (s’,a) = f s in a Main> runId $ runState 0 $ sequence [tick,tick,tick] [0,1,2] Main>

Summary: How to Add a Feature Define a class representing the feature to be added (StateMonad). Define a type parameterised on an underlying monad to represent actions supporting the feature (State). Define sequencing of actions (instance Monad). Define how it supports the feature (instance StateMonad). Define how to lift underlying actions (instance MonadTransformer). Define how to observe the result of an action (runState).

Another Example: Failure Add a possibility for actions to fail, and to handle failure. class Monad m => FailureMonad m where failure :: m a handle :: m a -> m a -> m a Applications in search and backtracking programs. Example: divide x y = if y==0 then return (x/y) else failure

Actions with Failure Allow actions to deliver a special result, meaning ”I failed”. newtype Failure m a = Failure (m (Maybe a)) data Maybe a = Just a | Nothing

Sequencing Failure Sequencing must check if the first action failed, and if so abort the second. instance Monad m => Monad (Failure m) where return x = Failure (return (Just x)) Failure m >>= h = Failure $ do a <- m case a of Nothing -> return Nothing Just x -> let Failure m’ = h x in m’

Supporting Failure instance Monad m => FailureMonad m where failure = Failure $ return Nothing Failure m `handle` Failure h = Failure $ do x <- m case x of Nothing -> h Just a -> return (Just a)

Lifting Actions to Failure instance Monad m => MonadTransformer Failure m where lift m = Failure $ do x <- m return (Just x) Lifting an action just makes it succeed (return Just something).

Observing Result of a Failure runFailure :: Failure m a -> m a runFailure (Failure m) = do Just a <- m return a What happens if the result is Nothing? Should runFailure handle this? NO! Handle failures in the monad! Main> runId $ runFailure $ return 2 `handle` return 3 2

Observing Result of a Failure runFailure :: Failure m a -> m a runFailure (Failure m) = do Just a <- m return a What happens if the result is Nothing? Should runFailure handle this? NO! Handle failures in the monad! Main> runId $ runFailure $ failure `handle` return 3 3

Combining Features Suppose we want to add State and Failure to a monad. example :: (StateMonad Integer m, FailureMonad m) => m Integer example = do tick failure `handle` do tick We can build a suitable monad in two ways: Failure (State Integer m) State Integer (Failure m) Need new instances: FailureMonad (State s m) StateMonad (Failure m) s

Sample Runs Main> runId $ runState 0 $ runFailure $ example 1 Main> runId $ runFailure $ runState 0 $ example 0 example :: (StateMonad Integer m, FailureMonad m) => m Integer example = do tick failure `handle` do tick

Sample Runs Main> runId $ runState 0 $ runFailure $ example 1 Main> runId $ runFailure $ runState 0 $ example 0 example :: (StateMonad Integer m, FailureMonad m) => m Integer example = do tick failure `handle` do tick Failure (State Integer Id) State Integer (Failure Id)

What are the types? Main> runId $ runState 0 $ runFailure $ example 1 Main> runId $ runFailure $ runState 0 $ example 0 Failure (State Integer Id) State Integer (Failure Id) Failure (State s m) a  s -> m (s, Maybe a) State s (Failure m) a  s -> m (Maybe (s, a)) Always yields a final state No state on failure

Why the Different Behaviour? Compare the instances of `handle`: instance FailureMonad m => FailureMonad (State s m) where State m `handle` State m' = State $ \s -> m s `handle` m' s instance Monad m => FailureMonad (Failure m) where Failure m `handle` Failure m' = Failure (do x <- m case x of Nothing -> m' Just a -> return (Just a)) Same state in handler. M is a state monad So state changes

Example: Parsing A parser can fail -- we handle failure by trying an alternative. A parser consumes input -- has a state, the input to parse. A failing parse should not change the state. type Parser m tok a = State [tok] (Failure m) a Type synonym -- not abstract We get for free: return x-- accept no tokens & succeed do syntax-- for sequencing failure-- the failing parser

Parsing a Token satisfy p = do s<-readState case s of [] -> failure x:xs -> if p x then do writeState xs return x else failure literal tok = satisfy (==tok)

Completing the Library p ||| q = p `handle` q many p = some p ||| return [] some p = liftM2 (:) p (many p) runParser p input = runFailure $ runState input $ p This completes the basic parsing library we saw in the previous lecture.

Summary Monads provide sequencing, and offer a general and uniform interface to many different DSELs. Monad transformers provide a systematic way to design and implement monads. Together with generic monadic code, they provide a lot of functionality “for free” to the DSEL implementor.