PROGRAMMING IN HASKELL

Slides:



Advertisements
Similar presentations
Functional Programming Universitatea Politehnica Bucuresti Adina Magda Florea
Advertisements

1 Introduction to Computability Theory Lecture12: Reductions Prof. Amos Israeli.
Six compound procedures and higher-order procedures.
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.
0 PROGRAMMING IN HASKELL Typeclasses and higher order functions Based on lecture notes by Graham Hutton The book “Learn You a Haskell for Great Good” (and.
Advanced Functional Programming Tim Sheard 1 Lecture 6 Functional Programming Tim Sheard & Mark Jones Monads & Interpreters.
0 Functors in Haskell Adapted from material by Miran Lipovaca.
© 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.
0 Odds and Ends in Haskell: Folding, I/O, and Functors Adapted from material by Miran Lipovaca.
CS2102: Lecture on Abstract Classes and Inheritance Kathi Fisler.
BIT 115: Introduction To Programming Professor: Dr. Baba Kofi Weusijana (say Doc-tor Way-oo-see-jah-nah, Doc-tor, or Bah-bah)
Module 9: Operator overloading #1 2000/01Scientific Computing in OOCourse code 3C59 Module 9: Operator Overloading In this module we will cover Overloading.
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.
0 PROGRAMMING IN HASKELL Typeclasses and higher order functions Based on lecture notes by Graham Hutton The book “Learn You a Haskell for Great Good” (and.
Advanced Functional Programming 2010
Polymorphic Functions
GCSE/IGCSE-FM Functions
JavaScript/ App Lab Programming:
Haskell: Syntax in Functions
Friend functions, operator overloading
Announcements Topics: To Do:
Theory of Computation Lecture 4: Programs and Computable Functions II
What to do when a test fails
CS 4450: Principles of Programming Languages
GC211Data Structure Lecture2 Sara Alhajjam.
Expanded Recursive Diagrams OCAML rapid tour, day 2
Trees.
Stack Data Structure, Reverse Polish Notation, Homework 7
CS2102: Lecture on Abstract Classes and Inheritance
PROGRAMMING IN HASKELL
More Selections BIS1523 – Lecture 9.
Pure Kevin Edelmann.
PROGRAMMING IN HASKELL
OOP Paradigms There are four main aspects of Object-Orientated Programming Inheritance Polymorphism Abstraction Encapsulation We’ve seen Encapsulation.
PROGRAMMING IN HASKELL
Haskell Dealing with impurity 30-Nov-18.
Theory of Computation Turing Machines.
PROGRAMMING IN HASKELL
Programming in JavaScript
Lecture 24 Logistics Last lecture Today HW7 due today
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
Coding Concepts (Standards and Testing)
Fundamentals of Data Representation
PROGRAMMING IN HASKELL
CSE341: Programming Languages Lecture 12 Equivalence
4. Computational Problem Solving
Trees.
Fundamentals of Functional Programming
Programming in JavaScript
ECE 352 Digital System Fundamentals
Functional Programming
Haskell Dealing with impurity 8-Apr-19.
Lecture 24 Logistics Last lecture Today HW7 due today
PROGRAMMING IN HASKELL
ECE 352 Digital System Fundamentals
Chapter 3 Debugging Section 3.4
Haskell Dealing with impurity 29-May-19.
CSE341: Programming Languages Lecture 12 Equivalence
PROGRAMMING IN HASKELL
Haskell Dealing with impurity 28-Jun-19.
Lecture 3 More on Flow Control, More on Functions,
Software Development Techniques
CS 5010 Program Design Paradigms “Bootcamp” Lesson 4.1
PROGRAMMING IN HASKELL
CSE341: Programming Languages Lecture 12 Equivalence
Presentation transcript:

PROGRAMMING IN HASKELL Monads and beyond Based on the Haskell wikibook, the book “Learn You a Haskell for Great Good”, (and a few other sources)

Fixed tree code I posted fixed code for our tree data class on the website. Notes: (on board) All examples from last time should run with this one.

Last time: Monads A monad is defined by 3 things: A type constructor m A function return An operator (>>=) – read as “bind” Main goal: provide even more general framework than functors for “mapping over things”. Result and main goal: modularity! Results in more powerful and compact code. Note that many consider these one of the most powerful (and difficult to understand) features of haskell.

Monads example: Maybe return :: a -> Maybe a return x = Just x (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b m >>= g = case m of Nothing -> Nothing Just x -> g x Maybe is the monad, and return brings a value into it by wrapping it with Just. As for (>>=), it takes a m :: Maybe a value and a g :: a -> Maybe b function. If m is Nothing, there is nothing to do and the result is Nothing. Otherwise, in the Just x case, g is applied to x, the underlying value wrapped in Just, to give a Maybe b result. To sum it all up, if there is an underlying value of type a in m, we apply g to it, which brings the underlying value back into the Maybe monad.

Monads: motivation Continuing this example: Imagine a family database with two functions, which look up the parents of a person: father :: Person -> Maybe Person mother :: Person -> Maybe Person The Maybe is there in case our database is missing some information. We then might want to build other functions, to look up grandparents, etc (next slide)

Monads: motivation Now, let’s find grandparents: maternalGrandfather :: Person -> Maybe Person maternalGrandfather p = case mother p of Nothing -> Nothing Just mom -> father mom But there’s a better way! Maybe is a monad, so can do: maternalGrandfather p = mother p >>= father

Monads: Even more drastic: Becomes: bothGrandfathers p = bothGrandfathers :: Person -> Maybe (Person, Person) bothGrandfathers p = case father p of Nothing -> Nothing Just dad -> case father dad of Just gf1 -> -- found first grandfather case mother p of Just mom -> case father mom of Just gf2 -> -- found second grandfather Just (gf1, gf2) Becomes: bothGrandfathers p = father p >>= (\dad -> father dad >>= (\gf1 -> mother p >>= -- gf1 is only used in the final return (\mom -> father mom >>= (\gf2 -> return (gf1,gf2) ))))

Monads: even better In fact, that grandfather example can be made even better if we use the do notation with braces and semi-colons. This will look more like imperative code that we’re used to! (Like IOs.) Here, father and mother are functions that might fail to produce results, i.e. raise an exception, and when that happens, the whole do-block will fail, i.e. terminate with an exception. bothGrandfathers p = do { dad <- father p; gf1 <- father dad; mom <- mother p; gf2 <- father mom; return (gf1, gf2); }

Monad laws Monads are required to obey 3 laws: Why?? m >>= return = m -- right unit return x >>= f = f x -- left unit (m >>= f) >>= g = m >>= (\x -> f x >>= g) -- associativity Why??

Another monad: lists Lists are another commonly used monad! Consider the following code: [(x,y) | x <- [1,2,3] , y <- [1,2,3], x /= y] This is list comprehension, like many we’ve seen so far. Output?

Another monad: lists This code: [(x,y) | x <- [1,2,3] , y <- [1,2,3], x /= y] Is actually equivalent to the following: do x <- [1,2,3] y <- [1,2,3] True <- return (x /= y) return (x,y) Here, each <- generates a set of values which are passed to the rest of the monadic expression. So x <- calls the rest 3 times, and the result (x,y) is returned once for each evaluation.

Applicative type class An applicative functor is something between a “normal” functor and a monad: it allows applying functions within the functor. The primary operation is <*>: GHCi> :t (<*>) (<*>) :: Applicative f => f (a -> b) -> f a -> f b For example: instance Applicative Maybe where pure = Just (Just f) <*> (Just x) = Just (f x) _ <*> _ = Nothing

Applicative type class Why? Makes life easier! Imagine if you wanted to sum Just 2 and Just 3 together. Brute force approach would be to extract values from the wrapper with pattern matching – annoying, since tons of Maybe checks. What we’d like is an operator something like f (a -> b) -> f a -> f b, so we can apply functions in the context of a functor. (Go check previous slide – that’s what <*> is!)

Applicative in action In action, it looks something like this: Prelude> (+) <$> Just 2 <*> Just 3 Just 5 Expressions such as this one are said to be written in applicative style, which is as close as we can get to regular function application while working with a functor. The other operation, pure, just wraps something up in context.

Applicative laws As with all of these, there are rules for this type class. pure id <*> v = v -- Identity pure f <*> pure x = pure (f x) -- Homomorphism u <*> pure y = pure ($ y) <*> u -- Interchange pure (.) <*> u <*> v <*> w = u <*> (v <*> w) -- Composition Again, these just keep things behaving like they should.

Applicative versus monad In fact, some similarities come out: pure :: Applicative f => a -> f a return :: Monad m => a -> m a The only difference is the class constraint (the m in the monad one). Really, pure and return serve the same purpose; that is, bringing values into functors.

Applicative functor: lists We can use <*> over lists, too: Prelude> [(2*),(5*),(9*)] <*> [1,4,7] [2,8,14,5,20,35,9,36,63] The only difference is the class constraint (the m in the monad one). Really, pure and return serve the same purpose; that is, bringing values into functors.

Recap: a sliding scale of power Functor, Applicative, and monad: ignoring pure and return, we get an increasing amount of power: fmap :: Functor f => (a -> b) -> f a -> f b (<*>) :: Applicative f => f (a -> b) -> f a -> f b (>>=) :: Monad m => m a -> (a -> m b) -> m b Rewording a bit: (<$>) :: Functor t => (a -> b) -> (t a -> t b) (<*>) :: Applicative t => t (a -> b) -> (t a -> t b) (=<<) :: Monad t => (a -> t b) -> (t a -> t b)

Recap: a sliding scale of power What does it mean?? (<$>) :: Functor t => (a -> b) -> (t a -> t b) (<*>) :: Applicative t => t (a -> b) -> (t a -> t b) (=<<) :: Monad t => (a -> t b) -> (t a -> t b) Armed with these functions, =<< is the only one which allows us to create contexts (a -> t b) with our inputs. Applicative allows only the combining of contexts we're bringing along. Functor allows no effects to the context at all.

Using these things Even if you never turn your data types into these, you use them constantly in Haskell – everything from lists on up builds upon these operations, and give Haskell its strength. However, making even basic data types in Haskell will be much easier if you give it some thought. There are many examples, from error message passing to finite state machines to complex data structures. (I’ll post a few links on the page for more reading, but most get too long to cover in a lecture!)