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

Similar documents
Software System Design and Implementation

Monads. COS 441 Slides 16

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

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

15-122: Principles of Imperative Computation (Section G)

CS 320: Concepts of Programming Languages

JVM ByteCode Interpreter

Lambda calculus. Wouter Swierstra and Alejandro Serrano. Advanced functional programming - Lecture 6

The Substitution Model

Overloading, Type Classes, and Algebraic Datatypes

CS 11 Haskell track: lecture 1

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

Programming Language Pragmatics

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

College Functors, Applicatives

The Substitution Model. Nate Foster Spring 2018

Haskell Refresher Informatics 2D

LECTURE 16. Functional Programming

CS 440: Programming Languages and Translators, Spring 2019 Mon

Denotational Semantics. Domain Theory

Programming Languages and Techniques (CIS120)

Monads. Functional Programming (CS4011) Monads

Functional Programming. Big Picture. Design of Programming Languages

Chapter 11 :: Functional Languages

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

Applicative, traversable, foldable

CSE341, Spring 2013, Final Examination June 13, 2013

Types of recursion. Structural vs. general recursion. Pure structural recursion. Readings: none. In this module: learn to use accumulative recursion

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

Applicative, traversable, foldable

Formal Semantics. Prof. Clarkson Fall Today s music: Down to Earth by Peter Gabriel from the WALL-E soundtrack

Handout 10: Imperative programs and the Lambda Calculus

Program Abstractions, Language Paradigms. CS152. Chris Pollett. Aug. 27, 2008.

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

Topic 7: Algebraic Data Types

Part 1. An Implementation of the Gale-Shapley Algorithm

Types of recursion. Readings: none. In this module: a glimpse of non-structural recursion. CS 135 Winter : Types of recursion 1

More Lambda Calculus and Intro to Type Systems

Outline. What is semantics? Denotational semantics. Semantics of naming. What is semantics? 2 / 21

INTRODUCTION TO HASKELL

Advanced Functional Programming

Imperative languages

Overview. Why Pointers?

Template Haskell based implementation of printf

GHCi: Getting started (1A) Young Won Lim 6/3/17

To figure this out we need a more precise understanding of how ML works

CITS3211 FUNCTIONAL PROGRAMMING. 7. Lazy evaluation and infinite lists

CS 381: Programming Language Fundamentals

Programming Systems in Artificial Intelligence Functional Programming

Functional Programming. Pure Functional Programming

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

To figure this out we need a more precise understanding of how ML works

Functional Programming

Tentamen Functioneel Programmeren 2001 Informatica, Universiteit Utrecht Docent: Wishnu Prasetya

A general introduction to Functional Programming using Haskell

Functional Languages. CSE 307 Principles of Programming Languages Stony Brook University

Programming Language Concepts, cs2104 Lecture 04 ( )

Intro to Haskell Notes: Part 5

CIS 194: Homework 3. Due Wednesday, February 11, Interpreters. Meet SImPL

G Programming Languages - Fall 2012

Principles of Programming Languages, Appendix

Fall 2018 Lecture 1

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

CS 11 Ocaml track: lecture 2

Fall Lecture 3 September 4. Stephen Brookes

Overview. Declarative Languages. General monads. The old IO monad. Sequencing operator example. Sequencing operator

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

CS4215 Programming Language Implementation. Martin Henz

C++ basics Getting started with, and Data Types.

GHCi: Getting started (1A) Young Won Lim 5/31/17

Case by Case. Chapter 3

More on functional programming

Functional Programming and Haskell

OCaml Language Choices CMSC 330: Organization of Programming Languages

CS 320: Concepts of Programming Languages

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

Functional Programming Languages (FPL)

Getting Started with Haskell (10 points)

All About Comonads (Part 1) An incomprehensible guide to the theory and practice of comonadic programming in Haskell

Lecture Notes on Contracts

G Programming Languages Spring 2010 Lecture 4. Robert Grimm, New York University

CSE341: Programming Languages Lecture 9 Function-Closure Idioms. Dan Grossman Winter 2013

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

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

Com S 541. Programming Languages I

Lecture 4: Higher Order Functions

CONVENTIONAL EXECUTABLE SEMANTICS. Grigore Rosu CS422 Programming Language Design

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

COP 4516: Math for Programming Contest Notes

Programming Languages. Function-Closure Idioms. Adapted from Dan Grossman's PL class, U. of Washington

Haskell An Introduction

Haskell through HUGS THE BASICS

Side Effects (3A) Young Won Lim 1/13/18

CS 320: Concepts of Programming Languages

A Pragmatic Case For. Static Typing

CS 457/557: Functional Languages

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

Introduction to Concepts in Functional Programming. CS16: Introduction to Data Structures & Algorithms Spring 2017

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

Products and Records

Transcription:

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

Reference "Monads for the Working Haskell Programmer" http://www.engr.mun.ca/~theo/misc/ haskell_and_monads.htm Good explanation of state monads Today's lecture shamelessly ripped off from this

Stateful computations (1) Most programming languages use state all over the place Functions can receive inputs, return outputs, and also modify the global state Internally, functions often work by modifying local state of function on a line-by-line basis

Stateful computations (2) Haskell is a purely functional programming language can t modify state locally or globally Can always turn a stateful computation into a stateless computation how?

Stateful computations (3) Can "thread the state" through functions by adding state as extra argument though functions become more cumbersome E.g. f(x) f(state, x) Managing threaded state becomes inconvenient How can we retain advantages of functional programming while still threading state?

Modeling state in Haskell (1) Recall that monads provide a way of structuring computations that are functionlike but not necessarily strictly functional We can create a monadic interface to functions that manipulate local state Conceptually, our "functions" will look like: local state input -------------> output

Modeling state in Haskell (2) To make this functional, we have to put the local state in the inputs and outputs as an additional argument in each: Now our functions look like this: (input, state) -> (state, output) The function takes in an input value, plus the initial value of the local state, and returns the output value, plus the final value of the local state

Modeling state in Haskell (3) We can curry the input argument to get: input -> state -> (state, output) This will be the characteristic shape of the monadic functions we'll be working with The monadic values will represent functions of the form state -> (state, output)

Modeling state in Haskell (4) Monadic functions: input -> state -> (state, output) Corresponds to a -> m b where a is input and m b is (state -> (state, output)) Monadic values: (state -> (state, output)) or m b for the appropriate monad m Real state monads are a thin wrapper around this notion

Running example Imperative algorithm to compute greatest common divisor (GCD) of two positive integers: int gcd(int x, int y) { while (x!= y) { } } if (x < y) else return x; y = y - x; x = x - y;

Stateful data types (1) First, want to encapsulate notion of threading state into our data types: newtype StateTrans s a = ST (s -> (s, a)) newtype declaration is like a data declaration with only one option Now a StateTrans object encapsulates some kind of state (s) and some kind of value (a)

Stateful data types (2) newtype StateTrans s a = ST (s -> (s, a)) Notice that this type defines a whole family of state-passing types For any given computation, must assign a particular kind of state and a particular kind of value Can specify how to combine different instances of this type

Stateful data types (3) Can probably assume that state type stays constant throughout computation represents all possible aspects of state in the computation e.g. as a tuple Value types may change for every step of the computation

State monads (1) Can think of stateful computation as a composition of several smaller stateful computations To manage different "notions of computation", we use monads IO computations that perform I/O Maybe computations that may fail List computations that may return multiple results StateTrans computations that transform state

State monads (2) Let's build up the instance declaration: instance Monad (StateTrans s) where -- return :: a -> StateTrans s a return x = ST (\s0 -> (s0, x)) return just returns a value, leaving the state unchanged

State monads (3) Still need the bind operator: -- (>>=) :: StateTrans s a -> -- (a -> StateTrans s b) -> -- StateTrans s b (ST p) >>= k = ST (\s0 -> let (s1, x) = p s0 (ST q) = k x in q s1)

State monads (4) Meaning of the bind operator: (ST p) >>= k = ST (\s0 -> let (s1, x) = p s0 (ST q) = k x in q s1) Given state transformer p, return new state transformer that takes a state s0, applies p to it to get (s1, x) applies k to x to get new state transformer ST q applies q to new state s1 to get final state/value pair

Useful auxiliary functions (1) -- Extract the state from the monad. readst :: StateTrans s s readst = ST (\s0 -> (s0, s0)) -- Update the state of the monad. updatest :: (s -> s) -> StateTrans s () updatest f = ST (\s0 -> (f s0, ()))

Useful auxiliary functions (2) -- Evaluate a stateful computation. runst :: StateTrans s a -> s -> (s, a) runst (ST p) s0 = p s0 This starts off the entire computation by passing a state to a particular transformer result is the final state/value pair

GCD example (1) The state represents? the current x and y values. type GCDState = (Int, Int)

GCD example (2) Getting values from the state: getx :: StateTrans GCDState Int -- getx = ST (\s0 -> (s0, fst s0)) getx = do s0 <- readst return (fst s0) gety :: StateTrans GCDState Int -- gety = ST (\s0 -> (s0, snd s0)) gety = do s0 <- readst return (snd s0)

GCD example (3) Evaluation of getx getx = do s0 <- readst return (fst s0) Desugar do, equivalent to: getx = readst >>= \s0 -> return (fst s0) Evaluate readst: getx = ST (\s0 -> (s0, s0)) >>= \s0 -> return (fst s0)

GCD example (4) Evaluation of getx getx = readst >>= \s0 -> return (fst s0) = ST (\s0 -> (s0, s0)) >>= \s0 -> return (fst s0) Unpack >>= operator for state monad Recall: (ST p) >>= k = ST (\s0 -> let (s1, x) = p s0 (ST q) = k x in q s1)

GCD example (5) getx = ST (\s0 -> (s0, s0)) >>= \s0 -> return (fst s0) (ST p) >>= k = ST (\s0 -> let (s1, x) = p s0 (ST q) = k x in q s1) Here, p s0 = (s0, s0) k = \s0 -> return (fst s0) getx = ST (\s0 -> let (s1, x) = (s0, s0) in q s1) (ST q) = return (fst s0)

GCD example (6) getx = ST (\s0 -> let (s1, x) = (s0, s0) Recall: return x = ST (\s0 -> (s0, x)) Therefore: ST q = ST (\s0 -> (s0, fst s0)) Continuing... getx = ST (\s0 -> q s1) (ST q) = return (fst s0) in q s1) = ST (\s0 -> q s0) -- s1 == s0 here = ST (\s0 -> (s0, fst s0)) -- QED

GCD example (7) Putting values into the state: putx :: Int -> StateTrans GCDState () -- putx x' = ST (\(x, y) -> ((x', y), ())) putx x' = updatest (\s0 -> (x', snd s0)) puty :: Int -> StateTrans GCDState () -- puty y' = ST (\(x, y) -> ((x, y'), ())) puty y' = updatest (\s0 -> (fst s0, y'))

GCD example (8) Compute the GCD: gcdst :: StateTrans GCDState Int gcdst = do x <- getx y <- gety (if x == y then return x else if x < y then do puty (y - x) gcdst else do putx (x - y) gcdst)

GCD example (9) Compute the GCD: gcdst :: StateTrans GCDState Int gcdst = do x <- getx y <- gety (if x == y then return x else if x < y then do puty (y - x) gcdst else do putx (x - y) gcdst) looks like recursive function call, but isn't really

GCD example (10) do puty (y - x) gcdst Equivalent to: puty (y - x) >> gcdst Combines two state transformers to get a new state transformer Recursive data definition not recursive function call like ones = 1 : ones

GCD example (11) Running the GCD: mygcd :: Int -> Int -> Int mygcd x y = snd (runst gcdst (x, y)) Initialize GCD state transformer with (x, y) Run it until it returns a final (state, value) pair Return the second element of the pair (the result value)

GCD example (12) Could write more helper functions e.g. whilest to more accurately imitate the imperative algorithm Common Haskell practice to write higherorder monad combinators

whilest (1) Let's try to write whilest State monad version of an imperative "while" loop Inputs? a "test" (to see if we continue the loop) a "body" (the contents of the loop) Output? a state transformer implementing the while loop

whilest (2) Type of the inputs? test a function mapping...? the state to a boolean (s -> Bool) body a state transformer returning...? nothing! (unit type ()) StateTrans s ()

whilest (3) Type of the output? a state transition returning...? nothing! (unit type ()) StateTrans s () The function thus has type (s -> Bool) -> StateTrans s () -> StateTrans s ()

whilest (4) whilest :: (s -> Bool) -> StateTrans s () -> StateTrans s () whilest test body = do s0 <- readst if (test s0) then do updatest (fst. b) else return () where ST b = body whilest test body

whilest (4) whilest :: (s -> Bool) -> StateTrans s () -> StateTrans s () whilest test body = do s0 <- readst if (test s0) then do updatest (fst. b) else return () where ST b = body read the current state whilest test body

whilest (4) whilest :: (s -> Bool) -> StateTrans s () -> StateTrans s () whilest test body = do s0 <- readst if (test s0) if the test is true then do updatest (fst. b) else return () where ST b = body whilest test body

whilest (4) whilest :: (s -> Bool) -> StateTrans s () -> StateTrans s () whilest test body = do s0 <- readst if (test s0) then do updatest (fst. b) else return () where ST b = body change the state using the body of the loop whilest test body

whilest (4) whilest :: (s -> Bool) -> StateTrans s () -> StateTrans s () whilest test body = do s0 <- readst if (test s0) then do updatest (fst. b) else return () where ST b = body whilest test body repeat the loop

whilest (4) whilest :: (s -> Bool) -> StateTrans s () -> StateTrans s () whilest test body = do s0 <- readst if (test s0) then do updatest (fst. b) else return () where ST b = body whilest test body otherwise, we're done

whilest (5) GCD function using whilest: gcdst :: StateTrans GCDState Int gcdst = do whilest (\(x, y) -> x /= y) (do x <- getx getx y <- gety if x < y then puty (y - x) else putx (x - y))

whilest (5) GCD function using whilest: gcdst :: StateTrans GCDState Int test gcdst = do whilest (\(x, y) -> x /= y) (do x <- getx getx y <- gety if x < y then puty (y - x) else putx (x - y))

whilest (5) GCD function using whilest: gcdst :: StateTrans GCDState Int gcdst = do whilest (\(x, y) -> x /= y) getx (do x <- getx y <- gety if x < y then puty (y - x) else putx (x - y)) body

whilest (5) GCD function using whilest: gcdst :: StateTrans GCDState Int gcdst = do whilest (\(x, y) -> x /= y) (do x <- getx getx y <- gety if x < y then puty (y - x) else putx (x - y)) result is x

whilest (6) Haskell C do whilest (\(x, y) -> x /= y) (do x <- getx y <- gety if x < y then puty (y - x) else putx (x - y)) getx while (x!= y) { if (x < y) { y = y - x; } else { x = x - y; } } return x;

What have we accomplished? We can now write any function in Haskell that would have used "internal state" in another language in essentially the same way Could have done this before if we were willing to convert imperative function into a functional form now we don't have to

Bottom line State monads can be used to implement imperative computations in a functional setting Requires a change of perspective: functions don't just map values to values functions map state transformers to state transformers monads make this convenient

Quote "Haskell is the world's best imperative language"

Warning! (1) Just because we can express stateful computations in Haskell, doesn't mean they run faster Sometimes, would like to write code in imperative style just so it runs faster (like raw C code) Haskell provides different tools to do this

Warning! (2) To represent the notion of a mutable value, can use IORef a -- mutable value of type a STRef a -- ditto IORef a runs in IO monad, STRef a runs in ST monad (which we haven't discussed) If you do this, code will run very fast

Next time Wrap up the lectures Module system Arrays "Maybe" some more monads