S*

Introduction To Haskell

Lecture 9


M.. M.. MONADS!

Using These Slides

Every slide has a secret note.

  • On Chrome: press F12, then click Console
  • On IE: press F12, then click Console
  • On Firefox: Ctrl+Shift+k


Shortcut Keys:

, PgDn, n, j next slide
, PgUp, p, k prev slide
Esc enables ctrl+f globally

Review of Homework 8

Write an IO program that reverses text
A
B
C
D

-- Designed by Eric J. Bomgardner 

module Main where

main = do
  theInput <- readFile "input.txt"
  writeFile "output.txt" (reverse theInput)
	    

The Maybe data type


data Maybe a = Nothing | Just a  
	      

Use Maybe when the output isn't guaranteed


Prelude> import Data.List

Prelude> :t elemIndex
elemIndex :: Eq a => a -> [a] -> Maybe Int
	      

Prelude Data.List> elemIndex 'b' "abc"
Just 1

Prelude Data.List> elemIndex 'z' "abc"
Nothing

	      

Context

Maybe wraps things into a context.


  • Just 1 vs 1

  • Just "hello" vs "hello"

  • Just 'a' vs 'a'

  • Nothing vs ERROR!

Functor

A Functor generalizes the map function

It implements fmap


fmap :: (a -> b) -> f a -> f b
	      

Naturally, a list derives the Functor Typeclass


Prelude> fmap (+1) [1,2,3]
[2,3,4]
	      

What else is a Functor?

Maybe is a Functor


*Main> fmap (+1) (Just 1)
Just 2
	      

IO is a Functor


*Main> fmap (++"!") getLine
hi
"hi!"
	      

The Functor Laws

Additionally, these rules are necessary to define a Functor.

First law:


fmap id F = F
	      

Second law:


fmap (f . g) F = fmap f (fmap g F)
	      

Applicative Typeclass


Prelude> import Control.Applicative

Prelude> (*) <$> Just 2 <*> Just 8  
Just 16
	      

We won't go into much detail about the Applicative Typeclass

There is a great introduction here

Monoid

A Monoid is a function (•) that satisfies the following:

  1. ∀ a,b ∈ S: a•b ∈ S

    The Set (S) is closed under the binary function (•).
  2. ∀ a,b,c ∈ S: (a•b)•c = a•(b•c)

    The binary function is associative
  3. ∃ e∈S: ∀ a∈S: e•a = a•e = a

    e is the identity element


(A Monoid is a Group without the requirement of an inverse) (Or a Category with a single object.)

Examples of Monoids

+ , 0 is a Monoid.


Which of the following are Monoids?

  • * , 1           , S={0,1,2,...}
  • || , False , S={True, False}
  • ++ , []       , S={"", "a", "ab",...}
  • ,           , S={A,B,...}
  • ÷ , 1           , S={1,2,...}

Try it out

In Haskell, the binary function is called mappend and its identity element is mempty


Prelude> import Data.Monoid

Prelude Data.Monoid> [1,2,3] `mappend` [4,5,6]
[1,2,3,4,5,6]

Prelude Data.Monoid> [1,2,3] `mappend` mempty
[1,2,3]

Prelude Data.Monoid> mempty `mappend` [1,2,3]
[1,2,3]

	      

As you can see above, lists are Monoids.

Quick Reminder

If you have a type a and a function a -> b

then you can get b.


Prelude> odd 3
True
	      

Maybe Continued

If we instead have m a and a function a -> m b

How would we get m b?


For example, given Maybe a and a -> Maybe b

How would we get Maybe b?


The answer we desire looks like this


(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
	      

>>= is called a bind

Necessity of bind

Let's say we had the function f below


f :: Int -> Maybe Int
f n = Just (n+1)
	      

Prelude> f 1
Just 2
	      

What if we wanted to pass in Just 1?


Prelude> f (Just 1)
ERROR!
	      

bind (>>=)


Prelude> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
	      

Prelude> Just 1 >>= f
Just 2
	      

The Monad Typeclass

A Monad is Typeclass with some extra rules.


The two important functions: return and >>=


return :: a -> m a  
  
(>>=) :: m a -> (a -> m b) -> m b  
	      

The >> function

This function simply glues together Monads.


Prelude> print "foo" >>= \_ -> print "bar"
"foo"
"bar"
	      

Prelude> print "foo" >> print "bar"
"foo"
"bar"
	      

The do notation is basically an interweaving of >>

main = do
  print "foo"
  print "bar"
	      

Minimize do usage

Write this piece of code without using do


main = do
  putStrLn "Enter name:"
  name <- getLine
  putStrLn ("Hi " ++ name)
	      

Try it out by yourself



main = putStrLn "Enter name:" >> getLine >>= putStrLn.("Hi " ++)
	      

Monad Laws

For something to truly be a Monad,

it must also obey the following laws: *


  • Left Identity

    return a >>= f   ≡   f a
  • Right Identity

    m >>= return   ≡   m
  • Associativity

    (m >>= f) >>= g   ≡   m >>= (\x -> f x >>= g)


These laws are somewhat similar to those of Monoids.

Monad Laws

Here's another way to write the three laws


do
  x' <- return x
  f x'

do
  f x

do
  x <- m
  return x

do
  m

do
  y <- do
    x <- m
    f x
  g y

do 
  x <- m
  y <- f x
  g y

It's based off the Kleisli composition operator *

(This is for your own curiosity.)

(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
	      

  • Left Identity

    return >=> g   ≡   g
  • Right Identity

    f >=> return   ≡   f
  • Associativity

    (f >=> g) >=> h   ≡   f >=> (g >=> h)

Why such specific rules?

These Monad laws form a mathematical category.


A monad in X is just a monoid in the category of endofunctors of X, with product × replaced by composition of endofunctors and unit set by the identity endofunctor.

-- Mac Lane


Monads are like burritos

-- Mark Dominus

Homework

  1. Fill out this week's form
  2. Think about final project ideas.
    • Building a SuDoKu solver
    • Building a personal finance software
    • Adding a library to Hackage
    • Using Haskell syntax as formal documentation
    • ...
    • etc.