Functors and Monads

Abstracting Code Patterns

a.k.a. Dont Repeat Yourself

Lists

Rendering the Values of a List

Squaring the values of a list










Common Pattern: map over a list

Refactor iteration into mapList

Reuse map to implement inc and sqr










Trees

Same “pattern” occurs in other structures!

Incrementing the values of a Tree

Squaring the values of a Tree









QUIZ: map over a Tree

Refactor iteration into mapTree! What should the type of mapTree be?









Lets write mapTree









QUIZ

Wait … there is a common pattern across two datatypes

Lets make a class for it!

What type should we give to gmap?










Reuse Iteration Across Types

Haskell’s libraries use the name Functor instead of Mappable

And now we can do

A Type to Represent Expressions








Some Example Expressions








EXERCISE: An Evaluator for Expressions

Fill in an implementation of eval

so that when you’re done we get

QUIZ

What does the following evaluate to?

A. 0 B. 1 C. Type error D. Runtime exception E. NaN











To avoid crash, return a Result

Lets make a data type that represents Ok or Error

EXERCISE

Can you implement a Functor instance for Result?

When you’re done you should see

Evaluating without Crashing

Instead of crashing we can make our eval return a Result Int

  • If a sub-expression has a divide by zero return Error "..."
  • If all sub-expressions are safe then return Ok n









EXERCISE: Implement eval with Result









The Good News

No nasty exceptions!









The BAD News!

The code is super gross

Escher’s Staircase
Escher’s Staircase









Lets spot a Pattern

The code is gross because we have these cascading blocks

but look closer … both blocks have a common pattern

  1. Evaluate e
  2. If the result is an Error then return that error.
  3. If the result is a Value v then further process with v.








Lets Bottle that Pattern in Two Functions

Bottling a Magic Pattern
Bottling a Magic Pattern
  • >>= (pronounced bind)
  • return (pronounced return)

NOTE: return is not a keyword

  • it is the name of a function!








A Cleaned up Evaluator

The magic bottle lets us clean up our eval

The gross pattern matching is all hidden inside >>=

Notice the >>= takes two inputs of type:

  • Result Int (e.g. eval e1 or eval e2)
  • Int -> Result Int (e.g. the processor takes the v and does stuff with it)

In the above, the processing functions are written using \v1 -> ... and \v2 -> ...

NOTE: It is crucial that you understand what the code above is doing, and why it is actually just a “shorter” version of the (gross) nested-case-of eval.








A Class for >>=

The >>= operator is useful across many types!

  • like fmap or show or toJSON or ==, or <=

Lets capture it in a typeclass:








Result is an instance of Monad

Notice how the definitions for Result fit the above, with m = Result








Syntax for >>=

In fact >>= is so useful there is special syntax for it.

Instead of writing

you can write

or if you like curly-braces









Simplified Evaluator

Thus, we can further simplify our eval to:

Which now produces the result