monads asking the right question

Post on 28-Jul-2015

127 Views

Category:

Internet

4 Downloads

Preview:

Click to see full reader

TRANSCRIPT

MonadsAsking the right question

WTF Monad?

In 30 minutes

WTF Monad?

“Hi”

“Sup?”

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

“Use IO Monad”

“What the *** is a monad?”

WTF Monad?

1. We understand code

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

then abstract to something more general

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

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

Code & related ideas

Android, iOS, Windows Phone

Partner Lookup

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

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

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

def partnerLookup(geek: Geek): String =

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

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")

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)

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)

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))

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))

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"

“This app sucks!”

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

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

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")

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)

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))

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 ...

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 ...

def partnerLookup(geek: Geek): String = {

}

def partnerLookup(geek: Geek): String = {

if(geek != null) { }

def partnerLookup(geek: Geek): String = {

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

def partnerLookup(geek: Geek): String = {

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

}

def partnerLookup(geek: Geek): String = {

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

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

}

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

} } } }}

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"}

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"

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"}

Call me: Maybe

sealed trait Maybe[+A]

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

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

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)}

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] {

}

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] {

}

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] {

}

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

}

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 =

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

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)

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)

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 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" }

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))

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"

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 = 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" }

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" }

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 = 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 =

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] =

with a little bit of magic

For-comprehension

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] = {

}

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._

}

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)

}

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)

}

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)

}

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)

}

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)

}

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)

}

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)

}

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

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

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

}

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 }

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

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 }

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}

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

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

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

partnerLookup(leonard)

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

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

Android, iOS, Windows Phone

Ship Inventory

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)

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))

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))

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))

sealed trait Many[+A]

sealed trait Many[+A]

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

sealed trait Many[+A]

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

case object Empty extends Many[Nothing]

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) : _*))

}

}

sealed trait Many[+A] {

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

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

}

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] = ...

}

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))

}

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))

}

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 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

}

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))

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)

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)

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)

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)

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)

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)

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)

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))

● We've seen two wrapping classes.

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

● 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).

Both were examples of a Monad!

WTF Monad?

Monad is a container, a box.

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

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.

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".

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.

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.

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.

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.

Monad is an abstract data type.

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

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

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

}

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

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

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

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

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

import Magic._

for {

p <- geek.partner

wp <- p.workPlace

s <- wp.street

} yield (s)

}

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

import Magic._

for {

p <- geek.partner

wp <- p.workPlace

s <- wp.street

} yield (s)

}

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)

}

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

import Magic._

for {

p <- geek.partner

wp <- p.workPlace

s <- wp.street

} yield (s)

}

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

for {

p <- geek.partner

wp <- p.workPlace

s <- wp.street

} yield (s)

}

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

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

1. associativity2. left identity3. right identity

unit acts approximately as a neutral element of bind

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

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

1. associativity2. left identity3. right identity

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

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”

WTF Monad?

Paweł Szulc

Paweł Szulchttp://rabbitonweb.com

Paweł Szulchttp://rabbitonweb.com

@rabbitonweb

Paweł Szulchttp://rabbitonweb.com

@rabbitonweb

Paweł Szulchttp://rabbitonweb.com

@rabbitonweb

Thank you!

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

top related