monads asking the right question

168
Monads Asking the right question

Upload: pawel-szulc

Post on 28-Jul-2015

127 views

Category:

Internet


4 download

TRANSCRIPT

Page 1: Monads  asking the right question

MonadsAsking the right question

Page 2: Monads  asking the right question

WTF Monad?

Page 3: Monads  asking the right question
Page 4: Monads  asking the right question
Page 5: Monads  asking the right question
Page 6: Monads  asking the right question
Page 7: Monads  asking the right question

In 30 minutes

Page 8: Monads  asking the right question

WTF Monad?

Page 9: Monads  asking the right question

“Hi”

Page 10: Monads  asking the right question

“Sup?”

Page 11: Monads  asking the right question

“I'm ready to write my first program. How can I print some stuff to console?”

Page 12: Monads  asking the right question

“Use IO Monad”

Page 13: Monads  asking the right question
Page 14: Monads  asking the right question
Page 15: Monads  asking the right question

“What the *** is a monad?”

Page 16: Monads  asking the right question

WTF Monad?

Page 17: Monads  asking the right question
Page 18: Monads  asking the right question
Page 19: Monads  asking the right question
Page 20: Monads  asking the right question

1. We understand code

Page 21: Monads  asking the right question

1. We understand code2. It is easier to talk about related ideas and

then abstract to something more general

Page 22: Monads  asking the right question

1. We understand code2. It is easier to talk about related ideas and

then abstract to something more general 3. Having abstract model created, we tend to

create metaphors

Page 23: Monads  asking the right question

1. We understand code2. It is easier to talk about related ideas and

then abstract to something more general 3. Having abstract model created, we tend to

create metaphors 4. Having all above we can formalize

Page 24: Monads  asking the right question

Code & related ideas

Page 25: Monads  asking the right question
Page 26: Monads  asking the right question

Android, iOS, Windows Phone

Partner Lookup

Page 27: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace)

Page 28: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace)case class WorkPlace(name: String, street: String)

Page 29: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace)case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String =

Page 30: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace)case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

Page 31: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace)case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

val cheeseCakeFactory = WorkPlace("Cheese Cake Factory", "Cake Street 1") val university = WorkPlace("University", "Academic St. 10")

Page 32: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace)case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

val cheeseCakeFactory = WorkPlace("Cheese Cake Factory", "Cake Street 1") val university = WorkPlace("University", "Academic St. 10") var penny = Geek("Penny", workPlace = cheeseCakeFactory) var leonard = Geek("Leonard", workPlace = university)

Page 33: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace)case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

val cheeseCakeFactory = WorkPlace("Cheese Cake Factory", "Cake Street 1") val university = WorkPlace("University", "Academic St. 10") var penny = Geek("Penny", workPlace = cheeseCakeFactory) var leonard = Geek("Leonard", workPlace = university)

penny = penny.copy(partner = leonard) leonard = leonard.copy(partner = penny)

Page 34: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace)case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

val cheeseCakeFactory = WorkPlace("Cheese Cake Factory", "Cake Street 1") val university = WorkPlace("University", "Academic St. 10") var penny = Geek("Penny", workPlace = cheeseCakeFactory) var leonard = Geek("Leonard", workPlace = university)

penny = penny.copy(partner = leonard) leonard = leonard.copy(partner = penny)

println(partnerLookup(leonard)) println(partnerLookup(penny))

Page 35: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace)case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

val cheeseCakeFactory = WorkPlace("Cheese Cake Factory", "Cake Street 1") val university = WorkPlace("University", "Academic St. 10") var penny = Geek("Penny", workPlace = cheeseCakeFactory) var leonard = Geek("Leonard", workPlace = university)

penny = penny.copy(partner = leonard) leonard = leonard.copy(partner = penny)

println(partnerLookup(leonard)) // output: "Cake Street 1" println(partnerLookup(penny))

Page 36: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace)case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

val cheeseCakeFactory = WorkPlace("Cheese Cake Factory", "Cake Street 1") val university = WorkPlace("University", "Academic St. 10") var penny = Geek("Penny", workPlace = cheeseCakeFactory) var leonard = Geek("Leonard", workPlace = university)

penny = penny.copy(partner = leonard) leonard = leonard.copy(partner = penny)

println(partnerLookup(leonard)) // output: "Cake Street 1" println(partnerLookup(penny)) // output: "Academic St. 10"

Page 37: Monads  asking the right question
Page 38: Monads  asking the right question
Page 39: Monads  asking the right question
Page 40: Monads  asking the right question

“This app sucks!”

Page 41: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace)case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

Page 42: Monads  asking the right question
Page 43: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace) case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

Page 44: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace) case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

val university = WorkPlace("University", "Academic St. 10")

Page 45: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace) case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

val university = WorkPlace("University", "Academic St. 10") val rajesh = Geek("Rajesh", workPlace = university)

Page 46: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace) case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

val university = WorkPlace("University", "Academic St. 10") val rajesh = Geek("Rajesh", workPlace = university)

println(partnerLookup(rajesh))

Page 47: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace) case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

val university = WorkPlace("University", "Academic St. 10") val rajesh = Geek("Rajesh", workPlace = university)

println(partnerLookup(rajesh))

// java.lang.NullPointerException

// at wtf.examples.A1$.partnerLookUp(A1.scala:14)

// at ...

Page 48: Monads  asking the right question

case class Geek(name: String, partner: Geek = null, workPlace: WorkPlace) case class WorkPlace(name: String, street: String)

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

val university = WorkPlace("University", "Academic St. 10") val rajesh = Geek("Rajesh", workPlace = university)

println(partnerLookup(rajesh))

// java.lang.NullPointerException

// at wtf.examples.A1$.partnerLookUp(A1.scala:14)

// at ...

Page 49: Monads  asking the right question

def partnerLookup(geek: Geek): String = {

}

Page 50: Monads  asking the right question

def partnerLookup(geek: Geek): String = {

if(geek != null) { }

Page 51: Monads  asking the right question

def partnerLookup(geek: Geek): String = {

if(geek != null) { if(geek.partner != null) { }

Page 52: Monads  asking the right question

def partnerLookup(geek: Geek): String = {

if(geek != null) { if(geek.partner != null) { if(geek.partner.workPlace != null) {

}

Page 53: Monads  asking the right question

def partnerLookup(geek: Geek): String = {

if(geek != null) { if(geek.partner != null) { if(geek.partner.workPlace != null) {

if(geek.partner.workPlace.street != null) {

}

Page 54: Monads  asking the right question

def partnerLookup(geek: Geek): String = {

if(geek != null) { if(geek.partner != null) { if(geek.partner.workPlace != null) {

if(geek.partner.workPlace.street != null) { return geek.partner.workPlace.street

} } } }}

Page 55: Monads  asking the right question

def partnerLookup(geek: Geek): String = {

if(geek != null) { if(geek.partner != null) { if(geek.partner.workPlace != null) {

if(geek.partner.workPlace.street != null) { return geek.partner.workPlace.street

} } } }

"not found"}

Page 56: Monads  asking the right question

val cheeseCakeFactory = WorkPlace("Cheese Cake Factory", "Cake Street 1") val university = WorkPlace("University", "Academic St. 10") var penny = Geek("Penny", workPlace = cheeseCakeFactory) var leonard = Geek("Leonard", workPlace = university) val rajesh = Geek("Rajesh", workPlace = university)

penny = penny.copy(partner = leonard) leonard = leonard.copy(partner = penny)

println(partnerLookup(leonard)) // output: "Cake Street 1" println(partnerLookup(penny)) // output: "Academic St. 10" println(partnerLookup(rajesh)) // output: "not found"

Page 57: Monads  asking the right question

def partnerLookup(geek: Geek): String = {

if(geek != null) { if(geek.partner != null) { if(geek.partner.workPlace != null) {

if(geek.partner.workPlace.street != null) { return geek.partner.workPlace.street

} } } }

"not found"}

Page 58: Monads  asking the right question

Call me: Maybe

Page 59: Monads  asking the right question

sealed trait Maybe[+A]

Page 60: Monads  asking the right question

sealed trait Maybe[+A] case class Some[+A](value: A) extends Maybe[A]

Page 61: Monads  asking the right question

sealed trait Maybe[+A] case class Some[+A](value: A) extends Maybe[A] case object None extends Maybe[Nothing]

Page 62: Monads  asking the right question

sealed trait Maybe[+A] case class Some[+A](value: A) extends Maybe[A] case object None extends Maybe[Nothing]

object Maybe { def apply[A](value: A) = Some(value)}

Page 63: Monads  asking the right question

sealed trait Maybe[+A] {

}object Maybe { def apply[A](value: A) = Some(value)}

case class Some[+A](value: A) extends Maybe[A] {

}

case object None extends Maybe[Nothing] {

}

Page 64: Monads  asking the right question

sealed trait Maybe[+A] { def andThen[B](f: A => Maybe[B]): Maybe[B] }object Maybe { def apply[A](value: A) = Some(value)}

case class Some[+A](value: A) extends Maybe[A] {

}

case object None extends Maybe[Nothing] {

}

Page 65: Monads  asking the right question

sealed trait Maybe[+A] { def andThen[B](f: A => Maybe[B]): Maybe[B] }object Maybe { def apply[A](value: A) = Some(value)}

case class Some[+A](value: A) extends Maybe[A] { def andThen[B](f: A => Maybe[B]): Maybe[B] = f(value) }

case object None extends Maybe[Nothing] {

}

Page 66: Monads  asking the right question

sealed trait Maybe[+A] { def andThen[B](f: A => Maybe[B]): Maybe[B] }object Maybe { def apply[A](value: A) = Some(value)}

case class Some[+A](value: A) extends Maybe[A] { def andThen[B](f: A => Maybe[B]): Maybe[B] = f(value) }

case object None extends Maybe[Nothing] { def andThen[B](f: Nothing => Maybe[B]): Maybe[B] = this

}

Page 67: Monads  asking the right question

case class Geek(name: String, partner: Maybe[Geek] = wtf.monads.None, workPlace: Maybe[WorkPlace])case class WorkPlace(name: String, street: Maybe[String])

def partnerLookup(geek: Geek): String =

Page 68: Monads  asking the right question

case class Geek(name: String, partner: Maybe[Geek] = wtf.monads.None, workPlace: Maybe[WorkPlace])case class WorkPlace(name: String, street: Maybe[String])

def partnerLookup(geek: Geek): String = geek.partner

Page 69: Monads  asking the right question

case class Geek(name: String, partner: Maybe[Geek] = wtf.monads.None, workPlace: Maybe[WorkPlace])case class WorkPlace(name: String, street: Maybe[String])

def partnerLookup(geek: Geek): String = geek.partner.andThen(g => g.workPlace)

Page 70: Monads  asking the right question

case class Geek(name: String, partner: Maybe[Geek] = wtf.monads.None, workPlace: Maybe[WorkPlace])case class WorkPlace(name: String, street: Maybe[String])

def partnerLookup(geek: Geek): String = geek.partner.andThen(g => g.workPlace).andThen(wp => wp.street)

Page 71: Monads  asking the right question

case class Geek(name: String, partner: Maybe[Geek] = wtf.monads.None, workPlace: Maybe[WorkPlace])case class WorkPlace(name: String, street: Maybe[String])

def partnerLookup(geek: Geek): String = geek.partner.andThen(g => g.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street }

Page 72: Monads  asking the right question

case class Geek(name: String, partner: Maybe[Geek] = wtf.monads.None, workPlace: Maybe[WorkPlace])case class WorkPlace(name: String, street: Maybe[String])

def partnerLookup(geek: Geek): String = geek.partner.andThen(g => g.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

Page 73: Monads  asking the right question

val cheeseCakeFactory = WorkPlace("Cheese Cake Factory", "Cake Street 1") val university = WorkPlace("University", "Academic St. 10") var penny = Geek("Penny", workPlace = cheeseCakeFactory) var leonard = Geek("Leonard", workPlace = university) val rajesh = Geek("Rajesh", workPlace = university)

penny = penny.copy(partner = leonard) leonard = leonard.copy(partner = penny)

println(partnerLookup(leonard)) println(partnerLookup(penny)) println(partnerLookup(rajesh))

Page 74: Monads  asking the right question

val cheeseCakeFactory = WorkPlace("Cheese Cake Factory", "Cake Street 1") val university = WorkPlace("University", "Academic St. 10") var penny = Geek("Penny", workPlace = cheeseCakeFactory) var leonard = Geek("Leonard", workPlace = university) val rajesh = Geek("Rajesh", workPlace = university)

penny = penny.copy(partner = leonard) leonard = leonard.copy(partner = penny)

println(partnerLookup(leonard)) // output: "Cake Street 1" println(partnerLookup(penny)) // output: "Academic St. 10" println(partnerLookup(rajesh)) // output: "not found"

Page 75: Monads  asking the right question

def partnerLookup(geek: Geek): String = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

Page 76: Monads  asking the right question

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

def partnerLookup(geek: Geek): String = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

Page 77: Monads  asking the right question

def partnerLookup(geek: Geek): String = geek.partner.workPlace.street

def partnerLookup(geek: Geek): String = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

Page 78: Monads  asking the right question

def partnerLookup(geek: Geek): String = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

Page 79: Monads  asking the right question

def partnerLookup(geek: Geek): String = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

def partnerLookup(geek: Geek): String =

Page 80: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

def partnerLookup(geek: Geek): Maybe[String] =

Page 81: Monads  asking the right question

with a little bit of magic

For-comprehension

Page 82: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

def partnerLookup(geek: Geek): Maybe[String] = {

}

Page 83: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

def partnerLookup(geek: Geek): Maybe[String] = { import Magic._

}

Page 84: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = geek.partner.andThen(g => g.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

def partnerLookup(geek: Geek): Maybe[String] = { import Magic._ for { p <- geek.partner wp <- p.workPlace s <- wp.street } yield (s)

}

Page 85: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

def partnerLookup(geek: Geek): Maybe[String] = { import Magic._ for { p <- geek.partner wp <- p.workPlace s <- wp.street } yield (s)

}

Page 86: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

def partnerLookup(geek: Geek): Maybe[String] = { import Magic._ for { p <- geek.partner wp <- p.workPlace s <- wp.street } yield (s)

}

Page 87: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

def partnerLookup(geek: Geek): Maybe[String] = { import Magic._ for { p <- geek.partner wp <- p.workPlace s <- wp.street } yield (s)

}

Page 88: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

def partnerLookup(geek: Geek): Maybe[String] = { import Magic._ for { p <- geek.partner wp <- p.workPlace s <- wp.street } yield (s)

}

Page 89: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

def partnerLookup(geek: Geek): Maybe[String] = { import Magic._ for { p <- geek.partner wp <- p.workPlace s <- wp.street } yield (s)

}

Page 90: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = geek.partner.andThen(p => p.workPlace).andThen(wp => wp.street) match { case wtf.monads.Some(street) => street case wtf.monads.None => "not found" }

def partnerLookup(geek: Geek): Maybe[String] = { import Magic._ for { p <- geek.partner wp <- p.workPlace s <- wp.street } yield (s)

}

Page 91: Monads  asking the right question

var leonard = Geek("Leonard", workPlace = university, partner = penny)

partnerLookup(leonard) // Some("Cake Street 1") // how to print it?

Page 92: Monads  asking the right question

sealed trait Maybe[+A] { def andThen[B](f: A => Maybe[B]): Maybe[B]

}object Maybe { def apply[A](value: A) = Some(value)}

case class Some[+A](value: A) extends Maybe[A] { def andThen[B](f: A => Maybe[B]): Maybe[B] = f(value)

}

case object None extends Maybe[Nothing] { def andThen[B](f: Nothing => Maybe[B]): Maybe[B] = this

}

Page 93: Monads  asking the right question

sealed trait Maybe[+A] { def andThen[B](f: A => Maybe[B]): Maybe[B] def within[B](f: A => B): Maybe[B]}object Maybe { def apply[A](value: A) = Some(value)}

case class Some[+A](value: A) extends Maybe[A] { def andThen[B](f: A => Maybe[B]): Maybe[B] = f(value) }

case object None extends Maybe[Nothing] { def andThen[B](f: Nothing => Maybe[B]): Maybe[B] = this }

Page 94: Monads  asking the right question

sealed trait Maybe[+A] { def andThen[B](f: A => Maybe[B]): Maybe[B] def within[B](f: A => B): Maybe[B]}object Maybe { def apply[A](value: A) = Some(value)}

case class Some[+A](value: A) extends Maybe[A] { def andThen[B](f: A => Maybe[B]): Maybe[B] = f(value) }

case object None extends Maybe[Nothing] { def andThen[B](f: Nothing => Maybe[B]): Maybe[B] = this }

Reuse existing functionality like println

Page 95: Monads  asking the right question

sealed trait Maybe[+A] { def andThen[B](f: A => Maybe[B]): Maybe[B] def within[B](f: A => B): Maybe[B]}object Maybe { def apply[A](value: A) = Some(value)}

case class Some[+A](value: A) extends Maybe[A] { def andThen[B](f: A => Maybe[B]): Maybe[B] = f(value) def within[B](f: A => B): Maybe[B] = Maybe(f(value))}

case object None extends Maybe[Nothing] { def andThen[B](f: Nothing => Maybe[B]): Maybe[B] = this }

Page 96: Monads  asking the right question

sealed trait Maybe[+A] { def andThen[B](f: A => Maybe[B]): Maybe[B] def within[B](f: A => B): Maybe[B]}object Maybe { def apply[A](value: A) = Some(value)}

case class Some[+A](value: A) extends Maybe[A] { def andThen[B](f: A => Maybe[B]): Maybe[B] = f(value) def within[B](f: A => B): Maybe[B] = Maybe(f(value))}

case object None extends Maybe[Nothing] { def andThen[B](f: Nothing => Maybe[B]): Maybe[B] = this def within[B](f: Nothing => B): Maybe[B] = this}

Page 97: Monads  asking the right question

var leonard = Geek("Leonard", workPlace = university, partner = penny)

partnerLookup(leonard) // Some("Cake Street 1") // how to print it?

Page 98: Monads  asking the right question

var leonard = Geek("Leonard", workPlace = university, partner = penny)

partnerLookup(leonard)

Page 99: Monads  asking the right question

var leonard = Geek("Leonard", workPlace = university, partner = penny)

partnerLookup(leonard).within(println) // output: "Cake Street 1"

Page 100: Monads  asking the right question
Page 101: Monads  asking the right question
Page 102: Monads  asking the right question

Android, iOS, Windows Phone

Ship Inventory

Page 103: Monads  asking the right question

case class Pirate(name: String, ships: Many[Ship])

case class Ship(name: String, hold: Hold)

case class Hold(barrel: Many[Barrel])

case class Barrel(amount: Int)

Page 104: Monads  asking the right question

case class Pirate(name: String, ships: Many[Ship])

case class Ship(name: String, hold: Hold)

case class Hold(barrel: Many[Barrel])

case class Barrel(amount: Int)

val jack = Pirate("Captain Jack Sparrow", Many(blackPearl, whitePearl))

Page 105: Monads  asking the right question

case class Pirate(name: String, ships: Many[Ship])

case class Ship(name: String, hold: Hold)

case class Hold(barrel: Many[Barrel])

case class Barrel(amount: Int)

val blackPearl = Ship("Black Pearl", blackHold)

val whitePearl = Ship("White Pearl", whiteHold)

val jack = Pirate("Captain Jack Sparrow", Many(blackPearl, whitePearl))

Page 106: Monads  asking the right question

case class Pirate(name: String, ships: Many[Ship])

case class Ship(name: String, hold: Hold)

case class Hold(barrel: Many[Barrel])

case class Barrel(amount: Int)

val blackHold = Hold(Empty)

val whiteHold = Hold(Many(Barrel(20), Barrel(10)))

val blackPearl = Ship("Black Pearl", blackHold)

val whitePearl = Ship("White Pearl", whiteHold)

val jack = Pirate("Captain Jack Sparrow", Many(blackPearl, whitePearl))

Page 107: Monads  asking the right question

sealed trait Many[+A]

Page 108: Monads  asking the right question

sealed trait Many[+A]

case class Const[+A](head: A, tail: Many[A]) extends Many[A]

Page 109: Monads  asking the right question

sealed trait Many[+A]

case class Const[+A](head: A, tail: Many[A]) extends Many[A]

case object Empty extends Many[Nothing]

Page 110: Monads  asking the right question

sealed trait Many[+A]

case class Const[+A](head: A, tail: Many[A]) extends Many[A]

case object Empty extends Many[Nothing]

object Many {

def apply[A](elements: A*): Many[A] = {

if(elements.length == 1) Const(elements(0), Empty)

else Const(elements(0), apply(elements.drop(1) : _*))

}

}

Page 111: Monads  asking the right question

sealed trait Many[+A] {

def andThen[B](f: A => Many[B]): Many[B]

def within[B](f: A => B): Many[B]

}

Page 112: Monads  asking the right question

case class Const[+A](head: A, tail: Many[A]) extends Many[A] {

def andThen[B](f: A => Many[B]): Many[B] = ...

def within[B](f: A => B): Many[B] = ...

}

Page 113: Monads  asking the right question

case class Const[+A](head: A, tail: Many[A]) extends Many[A] {

def andThen[B](f: A => Many[B]): Many[B] = ...

def within[B](f: A => B): Many[B] = Const(f(head), tail.within(f))

}

Page 114: Monads  asking the right question

case class Const[+A](head: A, tail: Many[A]) extends Many[A] {

def andThen[B](f: A => Many[B]): Many[B] =

concat( f(head), tail.andThen(f) )

def within[B](f: A => B): Many[B] = Const(f(head), tail.within(f))

}

Page 115: Monads  asking the right question

case class Const[+A](head: A, tail: Many[A]) extends Many[A] {

def andThen[B](f: A => Many[B]): Many[B] =

concat( f(head), tail.andThen(f) )

private def concat[A](first: Many[A],

second: Many[A]): Many[A] = { … }

def within[B](f: A => B): Many[B] = Const(f(head), tail.within(f))

}

Page 116: Monads  asking the right question

case class Const[+A](head: A, tail: Many[A]) extends Many[A] {

def andThen[B](f: A => Many[B]): Many[B] =

concat( f(head), tail.andThen(f) )

private def concat[A](first: Many[A],

second: Many[A]): Many[A] = { … }

def within[B](f: A => B): Many[B] = Const(f(head), tail.within(f))

}

case object Empty extends Many[Nothing] {

def andThen[B](f: Nothing => Many[B]): Many[B] = this

def within[B](f: Nothing => B): Many[B] = this

}

Page 117: Monads  asking the right question

val blackPearl = Ship("Black Pearl", Hold(Empty))

val whitePearl = Ship("White Pearl",

Hold(Many(Barrel(20), Barrel(10))))

val jack = Pirate("Captain Jack Sparrow", Many(blackPearl, whitePearl))

Page 118: Monads  asking the right question

val blackPearl = Ship("Black Pearl", Hold(Empty))

val whitePearl = Ship("White Pearl",

Hold(Many(Barrel(20), Barrel(10))))

val jack = Pirate("Captain Jack Sparrow", Many(blackPearl, whitePearl))

jack.ships.andThen(ship => ship.hold.barrel)

.within(barrel => barrel.amount)

Page 119: Monads  asking the right question

val blackPearl = Ship("Black Pearl", Hold(Empty))

val whitePearl = Ship("White Pearl",

Hold(Many(Barrel(20), Barrel(10))))

val jack = Pirate("Captain Jack Sparrow", Many(blackPearl, whitePearl))

jack.ships.andThen(ship => ship.hold.barrel)

.within(barrel => barrel.amount)

import Magic._

val amounts = for {

ship <- jack.ships

barrel <- ship.hold.barrel

} yield (barrel.amount)

Page 120: Monads  asking the right question

val blackPearl = Ship("Black Pearl", Hold(Empty))

val whitePearl = Ship("White Pearl",

Hold(Many(Barrel(20), Barrel(10))))

val jack = Pirate("Captain Jack Sparrow", Many(blackPearl, whitePearl))

jack.ships.andThen(ship => ship.hold.barrel)

.within(barrel => barrel.amount)

import Magic._

val amounts = for {

ship <- jack.ships

barrel <- ship.hold.barrel

} yield (barrel.amount)

Page 121: Monads  asking the right question

val blackPearl = Ship("Black Pearl", Hold(Empty))

val whitePearl = Ship("White Pearl",

Hold(Many(Barrel(20), Barrel(10))))

val jack = Pirate("Captain Jack Sparrow", Many(blackPearl, whitePearl))

jack.ships.andThen(ship => ship.hold.barrel)

.within(barrel => barrel.amount)

import Magic._

val amounts = for {

ship <- jack.ships

barrel <- ship.hold.barrel

} yield (barrel.amount)

Page 122: Monads  asking the right question

val blackPearl = Ship("Black Pearl", Hold(Empty))

val whitePearl = Ship("White Pearl",

Hold(Many(Barrel(20), Barrel(10))))

val jack = Pirate("Captain Jack Sparrow", Many(blackPearl, whitePearl))

jack.ships.andThen(ship => ship.hold.barrel)

.within(barrel => barrel.amount)

import Magic._

val amounts = for {

ship <- jack.ships

barrel <- ship.hold.barrel

} yield (barrel.amount)

Page 123: Monads  asking the right question

val blackPearl = Ship("Black Pearl", Hold(Empty))

val whitePearl = Ship("White Pearl",

Hold(Many(Barrel(20), Barrel(10))))

val jack = Pirate("Captain Jack Sparrow", Many(blackPearl, whitePearl))

jack.ships.andThen(ship => ship.hold.barrel)

.within(barrel => barrel.amount)

import Magic._

val amounts = for {

ship <- jack.ships

barrel <- ship.hold.barrel

} yield (barrel.amount)

Page 124: Monads  asking the right question

val blackPearl = Ship("Black Pearl", Hold(Empty))

val whitePearl = Ship("White Pearl",

Hold(Many(Barrel(20), Barrel(10))))

val jack = Pirate("Captain Jack Sparrow", Many(blackPearl, whitePearl))

jack.ships.andThen(ship => ship.hold.barrel)

.within(barrel => barrel.amount)

import Magic._

val amounts = for {

ship <- jack.ships

barrel <- ship.hold.barrel

} yield (barrel.amount)

Page 125: Monads  asking the right question

val blackPearl = Ship("Black Pearl", Hold(Empty))

val whitePearl = Ship("White Pearl",

Hold(Many(Barrel(20), Barrel(10))))

val jack = Pirate("Captain Jack Sparrow", Many(blackPearl, whitePearl))

jack.ships.andThen(ship => ship.hold.barrel)

.within(barrel => barrel.amount)

import Magic._

val amounts = for {

ship <- jack.ships

barrel <- ship.hold.barrel

} yield (barrel.amount)

println(amounts) // Const(20,Const(10,Empty))

Page 126: Monads  asking the right question
Page 127: Monads  asking the right question

● We've seen two wrapping classes.

Page 128: Monads  asking the right question

● We've seen two wrapping classes. ● All have andThen method.

Page 129: Monads  asking the right question

● We've seen two wrapping classes. ● All have andThen method.● Each can take a function that can be called

on a value wrapped by the structure (which can be empty or there can be multiple instances of it).

Page 130: Monads  asking the right question

Both were examples of a Monad!

Page 131: Monads  asking the right question

WTF Monad?

Page 132: Monads  asking the right question

Monad is a container, a box.

Page 133: Monads  asking the right question

Monad is a container, a box.A box in which we can store an object. Wrap it.

Page 134: Monads  asking the right question

Monad is a container, a box.A box in which we can store an object, a value.A box that has a common interface, which allows us to do one thing: connect sequence of operations on the content of the box.

Page 135: Monads  asking the right question

Monad is a container, a box.A box in which we can store an object, a value.A box that has a common interface, which allows us to do one thing: connect sequence of operations on the content of the box.andThen means "do the next things".

Page 136: Monads  asking the right question

Monad is a container, a box.A box in which we can store an object, a value.A box that has a common interface, which allows us to do one thing: connect sequence of operations on the content of the box.andThen means "do the next things". But the way it is done depends on a box.

Page 137: Monads  asking the right question

Monad is a container, a box.A box in which we can store an object, a value.A box that has a common interface, which allows us to do one thing: connect sequence of operations on the content of the box.andThen means "do the next things". But the way it is done depends on a box.

Page 138: Monads  asking the right question

Monad is a container, a box.A box in which we can store an object, a value.A box that has a common interface, which allows us to do one thing: connect sequence of operations on the content of the box.andThen means "do the next things". But the way it is done depends on a box.

Page 139: Monads  asking the right question

Monad is a container, a box.A box in which we can store an object, a value.A box that has a common interface, which allows us to do one thing: connect sequence of operations on the content of the box.andThen means "do the next things". But the way it is done depends on a box.

Page 140: Monads  asking the right question
Page 141: Monads  asking the right question

Monad is an abstract data type.

Page 142: Monads  asking the right question

Monad is an abstract data type.It has two operators: andThen and unit

Page 143: Monads  asking the right question

Monad is an abstract data type.It has two operators: andThen and unit

object Maybe { def apply[A](value: A) = Some(value)

}

Page 144: Monads  asking the right question

Monad is an abstract data type.It has two operators: andThen and unit

Page 145: Monads  asking the right question

Monad is an abstract data type.It has two operators: andThen and unit

Page 146: Monads  asking the right question

Monad is an abstract data type.It has two operators: andThen and unit bind (>>=) // formal name

Page 147: Monads  asking the right question

Monad is an abstract data type.It has two operators: andThen and unit bind (>>=) // formal name flatMap // in Scala

Page 148: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = {

import Magic._

for {

p <- geek.partner

wp <- p.workPlace

s <- wp.street

} yield (s)

}

Page 149: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = {

import Magic._

for {

p <- geek.partner

wp <- p.workPlace

s <- wp.street

} yield (s)

}

Page 150: Monads  asking the right question

object Magic {

case class RichMaybe[A](m: Maybe[A]) {

def flatMap[B](f: A => Maybe[B]): Maybe[B] = m.andThen(f)

def map[B](f: A => B): Maybe[B] = m.within(f)

}

implicit def enrich[A](m: Maybe[A]) = RichMaybe(m)

}

Page 151: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = {

import Magic._

for {

p <- geek.partner

wp <- p.workPlace

s <- wp.street

} yield (s)

}

Page 152: Monads  asking the right question

def partnerLookup(geek: Geek): Maybe[String] = {

for {

p <- geek.partner

wp <- p.workPlace

s <- wp.street

} yield (s)

}

Page 153: Monads  asking the right question

Monad is an abstract data type.It has two operators: bind and unit

Page 154: Monads  asking the right question

Monad is an abstract data type.It has two operators: bind and unitThose operators must follow certain rules:1. associativity2. left identity3. right identity

Page 155: Monads  asking the right question

1. associativity2. left identity3. right identity

unit acts approximately as a neutral element of bind

Page 156: Monads  asking the right question

1. associativity2. left identity3. right identity

unit acts approximately as a neutral element of bind

unit allows us to put value into the box without damaging it

Page 157: Monads  asking the right question

1. associativity2. left identity3. right identity

unit acts approximately as a neutral element of bind

unit(x).flatMap(f) == f(x)m.flatMap(unit) == m

unit allows us to put value into the box without damaging it

Page 158: Monads  asking the right question

1. associativity2. left identity3. right identity

“Binding two functions in succession is the same as binding one function that can be determined from them”

Page 159: Monads  asking the right question

1. associativity2. left identity3. right identity

m.flatMap{f(_)}.flatMap.{g(_)} ==m.flatMap{f(_).flatMap.{g(_)}}

“Binding two functions in succession is the same as binding one function that can be determined from them”

Page 160: Monads  asking the right question

WTF Monad?

Page 161: Monads  asking the right question

Paweł Szulc

Page 162: Monads  asking the right question

Paweł Szulchttp://rabbitonweb.com

Page 163: Monads  asking the right question

Paweł Szulchttp://rabbitonweb.com

@rabbitonweb

Page 164: Monads  asking the right question

Paweł Szulchttp://rabbitonweb.com

@rabbitonweb

Page 165: Monads  asking the right question

Paweł Szulchttp://rabbitonweb.com

@rabbitonweb

Page 167: Monads  asking the right question

Thank you!

Page 168: Monads  asking the right question

Images usedhttp://beforeitsnews.com/business/2014/02/career-tips-how-to-look-presentable-for-a-job-interview-2591264.html

http://phantommagician.deviantart.com/art/Cursed-Gold-183261313

http://carlosandgabbysbrooklyn.com/Burritos.html

http://channel9.msdn.com/Forums/Coffeehouse/442850-Sign-up-for-American-Programmer-C9park

https://www.pinterest.com/sandinarvaez/cute-graphics-and-patterns/

http://dsmconsulting.com.au/whats-in-the-box/

http://www.concordmonitor.com/home/4293575-95/cat-cats-videos-henri

https://www.pinterest.com/JoanneBest3/cats-in-boxes/

http://essaylab.org/

http://www.fanpop.com/clubs/pirates-of-the-caribbean/

http://library.sun.ac.za/SiteCollectionImages/search/Launch-Button.jpg