SlideShare ist ein Scribd-Unternehmen logo
1 von 126
Downloaden Sie, um offline zu lesen
FUNCTORS, APPLY,
APPLICATIVE AND
MONADS
THAT'S JUST DULL
SO LET'S TRY INSTEAD ...
.
WHY SHOULD YOU
CARE?
How do Functors, Apply, Applicative and Monad help you
achieve early and continuous delivery of software?
3 CONCEPTS
IF A PIZZA COSTS $16 AND YOU BUY
TWO HOW MUCH DO YOU SPEND?
A MARIO KART COSTS $20 PER DAY
TO RENT. HOW MUCH DOES IT COST
TO RENT FOR TWO DAYS?
DON'T JUST THINK ABOUT THE
MATHS
Think about the process you are going through before you
get to the maths.
What information are you keeping and what information are
you dropping?
.
ABSTRACTION
Abstraction is an emphasis on the idea, qualities and
properties rather than the particulars
The importance of abstraction is derived from its ability to
hide irrelevant details
It doesn't matter if its pizza, mario carts or anything else we
take the cost and muliply it by some factor.
WHAT IS THE REALATION SHIP
BETWEEN A POLOGON:
A 3 sided triangle
A 4 sided quadrilateral
WHAT HAS AM × AN = AM+N GOT IN
COMMON WITH:
a2 × a3 = (a × a) × (a × a × a) = a5
a3 × a4 = (a × a × a) × (a × a × a × a) = a7
.
GENERALIZATION
Relationship that holds between all members of some set of
objects
IS A MILE A LONG WAY?
IS A YEAR A LARGE AMOUNT OF
TIME?
.
IT ALL DEPENDS ON
CONTEXT
A mile is along way if you are an Ant but not if you are
flying in an aeroplane.
A year is a long time for a Mayfly that lives for only 5
minutes. But in geological time it's insignificant.
TRAINING LEVEL
WHAT IS FUNCTIONAL
PROGRAMMING?
Construct our programs using only pure
functions.
Pure functions have no side effects.
WHY IS A FUNCTION
LIKE A PIPE?
Some thing goes into one end and something else comes
out the other end
Simple pipes simple can be joined together to form complex
systems?
WHAT'S SO GOOD ABOUT NO SIDE
EFFECTS?
It makes it easier to reason about what's going on
IT'S IMPORTANT THAT FUNCTIONS
LIKE PIPES DON'T LEAK
WORLD 1-1
Functor Land
GOOMBA PROBLEM
HOW TO DEFEAT A GOOMBA
Stomp it and it turns into a coin
case class Coin()
case class Goomba()
def stomp(g:Goomba) = Coin()
The function stomp is our pipe, that transforms from a
Goomba to a Coin.
LUIGIS VACUUM TO COLLECT
GOOMBAS
class Vacuum {
def collect(g:Goomba) = stomp(s)
}
val vacuum = new Vacuum()
val goomba = new Goomba()
vacuum.collect(goomba)
//Coin()
WHAT HAPPENS WHEN THE
GOOMBA ESCAPES THE SUCTION?
val vacuum = new Vacuum()
vacuum.collect(null)
.
CHECK FOR NULLS
class Vacuum {
def collect(s:Goomba) = if (s == null) null else stomp(s)
}
But then the calling class runs the risk of NullPointer
exceptions.
There must be a better way
SOLUTION
Put the Goomba in a Cage
sealed trait Cage[T]
case class FullCage[T](value: T) extends Cage[T]
case class EmptyCage[T]() extends Cage[T]
object Cage {
def apply[T](x: T):Cage[T] =
if (x == null) EmptyCage[T]() else FullCage(x)
}
class Vacuum {
def collect(c:Cage[Goomba]):Cage[Coin] = c match {
case EmptyCage() => EmptyCage[Coin]()
case FullCage(s) => FullCage(stomp(s))
}
}
val vac = new Vacuum()
vac.collect(Cage(Goomba()))
//FullCage[Coin](Coin())
vac.collect(Cage(null))
//EmptyCage[Coin]()
.
CAN WE GENERALIZE
THE VACUUM CLASS?
WHY LIMIT OURSELF TO JUST
STOMPING GOOMBAS IN THE CAGE?
class Vacuum {
def collect[A,B](c:Cage[A], f:A => B):Cage[B] = c match {
case EmptyCage() => EmptyCage[B]()
case FullCage(s) => FullCage(f(s))
}
}
Turn it into a trait
trait Collector {
def collect[A,B](c:Cage[A], f:A => B):Cage[B]
}
class Vacuum extends Collector {
def collect[A,B](c:Cage[A], f:A => B):Cage[B] = c match {
case EmptyCage() => EmptyCage[B]()
case FullCage(s) => FullCage(f(s))
}
}
Parameterise the trait
trait Collector[F[_]] {
def collect[A,B](c:F[A], f:A => B): F[B]
}
object Vacuum extends Collector[Cage] {
def collect[A,B](c:Cage[A], f:A => B):Cage[B] = c match {
case EmptyCage() => EmptyCage[B]()
case FullCage(s) => FullCage(f(s))
}
}
.
THE FUNCTOR
A functor is basically for things that can be
mapped over.
THE FUNCTOR
DEFINITION IN SCALAZ
package scalaz
trait Functor[F[_]] extends InvariantFunctor[F] { self =>
...
/** Lift `f` into `F` and apply to `F[A]`. */
def map[A, B](fa: F[A])(f: A => B): F[B]
...
}
HOW DO YOU USE IT?
object CageFunctor extends Functor[Cage] {
def map[A,B](c:Cage[A])(f:A => B):Cage[B] = c match {
case EmptyCage() => EmptyCage[B]()
case FullCage(s) => FullCage(f(s))
}
}
CageFunctor.map(Cage(Gummba()))(stomp)
IS THERE A BETTER
WAY?
.
TYPE CLASSES IN 60
SECONDS
WHY?
Extend existing classes
Without inheritance
Without altering original source
Keeps concerns seperate
HOW?
3 COMPONENTS
1. The type class
2. Instances for particular types
3. Interface methods for the api
THE TYPE CLASS
Provide a generic type of what we want to implement.
trait ProtoBuffWriter[A] {
def write(value: A): Array[Byte]
}
TYPE CLASS INSTANCES
Provide implementations for the types we care about.
Create concrete implementations of the type class and mark
them as implicit.
object DefaultProtoBuffWriters {
implicit val coinWriter = ProtoBuffWriter[Coin] { .... }
implicit val goombaWriter = ProtoBuffWriter[Goomba] { .... }
// etc ...
}
INTERFACES
What is exposed to clients.
Generic methods that accept instances of the type class as
implicit params.
TWO WAYS OF DOING IT
INTERFACE OBJECTS
All methods in a singleton.
object ProtoBuff {
def toProtoBuff[A](value: A)
(implicit writer: ProtoBuffWriter[A]): Array[Byte] {
writer.write(value)
}
}
import DefaultProtoBuffWriters._
val protoBuff: Array[Byte] = ProtoBuff.toProtoBuff(Coin())
INTERFACE SYNTAX
Pimp existing types with interface methods.
object ProtoBuffSyntax {
implicit class ProtoBuffWriter[A](value: A) {
def toProtoBuff(implicit writer: ProtoBuffWriter[A])
: Array[Byte] = {
writer.write(value)
}
}
}
import DefaultProtoBuffWriters._
import ProtBuffSyntax._
val protoBuff: Array[Byte] = Coin().toProtoBuff
WHAT ABOUT SCALAZ?
Pimp existing types
Uses the Type classes in Ops classes
Ops classes use the Type class and provide more methods
import scala.language.implicitConversions
sealed trait ToProtoBuffWriterOps {
implicit def ToProtoBuffWriterOps[A](v: A)
(implicit F: ProtoBuffWriter[A]) = new ProtoBuffWriterOps(v)
}
object protoBuffWriter extends ToProtoBuffWriterOps
import sun.misc.BASE64Encoder //for example only
class ProtoBuffWriterOps[A](val self: A)
(implicit val F: ProtoBuffWriter[A]) {
def write(value: A) = F.write(value)
def writeBase64(value: A) =
new BASE64Encoder().encodeBuffer(write(value))
}
!!WARNING!!
Implicits like warp pipes can be dangerous
SCALAZ FUNCTOR SYNTAX:
TOFUNCTOROPS
scalaz.syntax.FunctorSyntax.scala
trait ToFunctorOps extends ToFunctorOps0 with ToInvariantFunctorOps
{
implicit def ToFunctorOps[F[_],A](v: F[A])(implicit F0: Functor[F])
= new FunctorOps[F,A](v)
...
}
Given a F[A] and a implicit Functor[F] in scope add all the
FunctorOps to F[A]
SCALAZ FUNCTOR SYNTAX:
FUNCTOROPS
scalaz.syntax.FunctorSyntax.scala
final class FunctorOps[F[_],A] private[syntax]
(val self: F[A])(implicit val F: Functor[F]) extends Ops[F[A]] {
...
final def map[B](f: A => B): F[B] = F.map(self)(f)
...
}
Given a F[A] and a implicit Functor[F] in scope delegate the
map method to the Functor[F] in scope
FINALLY
scalaz.syntax package object extends Syntaxes
trait Syntaxes {
object functor extends ToFunctorOps
}
import scalaz.syntax.functor
CAGE FUNCTOR AGAIN
scalaz.syntax.FunctorSyntax.scala
import scalaz.Functor
implicit object CageFunctor extends Functor[Cage] {
def map[A,B](c:Cage[A])(f:A => B):Cage[B] = c match {
case EmptyCage() => EmptyCage[B]()
case FullCage(s) => FullCage(f(s))
}
}
import scalaz.syntax.functor
Cage(Goomba()).map(stomp)
THE FUNCTOR LAWS
Mapping preserves identity
If we map the id function over a functor, the
functor that we get back should be the
same as the original functor
Mapping respects composition
Composing two functions and then
mapping the resulting function over a
functor should be the same as first
mapping one function over the functor and
then mapping the other one
DOES YOUR FUNCTOR BREAK LAWS?
import org.scalacheck.Arbitrary
import org.specs2.scalaz.Spec
import scalaz.Equal
import scalaz.scalacheck.ScalazProperties
class CageFunctorSpec extends Spec {
implicit val abrCage = Arbitrary[Cage[Int]] {
for {
ns <- Arbitrary.arbInt.arbitrary
} yield Cage(ns)
}
implicit val cageEqual = Equal.equal[Cage[Int]]((a, b) => a == b)
checkAll(ScalazProperties.functor.laws[Cage])
}
val scalazVersion = "7.1.3"
libraryDependencies ++= Seq(
"org.scalaz" %% "scalaz-core" % scalazVersion,
"org.specs2" %% "specs2-core" % "2.4" % "test",
"org.typelevel" %% "scalaz-specs2" % "0.3.0" % "test"
)
REMEMBER THE THREE POINTS?
Abstraction: Functor is a abstract concept
Generalization: There is a set of objects that can be
mapped over
What about the context?
CONTEXT
Context is the environment the function is applied in.
MEET SOME MORE
CONTEXTS
SCALA.OPTION
sealed abstract class Option[+A] extends Product with Serializable {
...
final def map[B](f: A => B): Option[B] =
if (isEmpty) None else Some(f(this.get))
...
}
Scalaz provides implicits to convert Option to a Functor trait
import scalaz.std.option._
import scalaz.std.anyVal._
checkAll(ScalazProperties.functor.laws[Option])
Option is context for a computation that might fail
LIST ARE ALSO FUNCTORS
sealed abstract class List[+A] { ....
final def map[B](f: (A) ⇒ B): List[B]
...
}
Scalaz provides implicits to convert List to a Functor trait
import scalaz.std.list._
import scalaz.std.anyVal._
import org.specs2.scalaz.Spec
import scalaz.scalacheck.ScalazProperties
class ListFunctorSpec extends Spec {
checkAll(ScalazProperties.functor.laws[List])
}
If 6 is deterministic and having one value.
The List context such as List(1,10,3,4) can be thought of as
having multipule values at once.
Or no values if empty
DISJUNCTIONS ARE FUNCTORS
import org.specs2.scalaz.Spec
import scalaz.scalacheck.ScalazProperties
class ListFunctorSpec extends Spec {
implicit val abrStringIntEither = Arbitrary[/[String, Int]] {
for {
ns <- Arbitrary.arbInt.arbitrary
} yield /-(ns)
}
implicit val disjuncEqual =
Equal.equal[/[String, Int]]((a, b) => { (a,b) match {
case(-/(l1), -/(l2)) => l1 == l2
case(/-(r1), /-(r2)) => r1 == r2
case _ => false
}
})
//left type param is fixed
checkAll(ScalazProperties.functor.laws[({type λ[α] = /[String, α]})#λ])
}
SO WHY IS THIS SO
HANDY?
ORDINARY FUNCTIONS ARE SIMPLER
TO:
read
write
use
reason about
FUNCTIONS IN A CONTEXT HAVE
USEFUL PROPERTIES
Functors let us write ordinary functions
Then promote those functions into every context that might
need that code
As new contexts arise we just define new functors to
promote our ordinary code to work in those contexts.
///Ordinary function
def stomp(g:Goomba) = g.stomp()
///The context
sealed trait Cage[T]
case class FullCage[T](value: T) extends Cage[T]
case class EmptyCage[T]() extends Cage[T]
object Cage {
def apply[T](x: T):Cage[T] =
if (x == null) EmptyCage[T]() else FullCage(x)
}
///Promote into context
import scalaz.Functor
implicit object CageFunctor extends Functor[Cage] {
def map[A,B](c:Cage[A])(f:A => B):Cage[B] = c match {
case EmptyCage() => EmptyCage[B]()
case FullCage(s) => FullCage(f(s))
}
}
///use
import scalaz.syntax.functor
Cage(Goomba()).map(stomp)
.
WORLD 1-2
Apply Land
PIRANHA PLANT
PIRANHA PLANT
case class Coin()
case class Fireball()
case class PiranhaPlant()
def shoot(plant:PiranhaPlant, fireball:Fireball): Coin = Coin()
THE PLANT IS GENERATED FROM A
UNRELIABLE SOURCE
Wrap the plant in a Cage and map over it?
Cage(PiranhaPlant()).map(shoot _)
<console>:31: error: type mismatch;
found : (PiranhaPlant, Fireball) => Coin
required: PiranhaPlant => ?
Cage(PiranhaPlant()).map(shoot _)
</console>
CURRING
CURRING IS PARTIAL APPLICATION
Translating the evaluation of a function that takes multiple
arguments into evaluating a sequence of functions, each
with a single argument
(shoot _).curried
//res41: PiranhaPlant => (Fireball => Coin) = <function1>
</function1>
MAP THE CURRIED SHOOT FUNCTION
Cage(PiranhaPlant()) map {shoot _}.curried
//Cage[Fireball => Coin] = ...
WHAT IF THE FIREBALL PARAMETER
GENERATION IS IN A CONTEXT?
Functor only support mapping functions over functor
def map[A, B](fa: F[A])(f: A => B): F[B]
We need to map function in a functor over a value in a
functor
APPLY
package scalaz
trait Apply[F[_]] extends Functor[F] { self =>
////
def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B]
...
}
package scalaz
package syntax
final class ApplyOps[F[_],A] private[syntax](val self: F[A])
(implicit val F: Apply[F]) extends Ops[F[A]] {
final def <*>[B](f: F[A => B]): F[B] = F.ap(self)(f)
...
}
trait ToApplyOps extends ToApplyOps0 with ToFunctorOps {
implicit def ToApplyOps[F[_],A](v: F[A])(implicit F0: Apply[F]) =
new ApplyOps[F,A](v)
...
}
WHAT WOULD OUR VACUUM LOOK LIKE?
implicit object CageApply extends Apply[Cage]{
override def ap[A, B](fa: => Cage[A])
(fab: => Cage[(A) => B]): Cage[B] = fab match {
case FullCage(f) => fa match {
case FullCage(x) => FullCage(f(x))
case EmptyCage() => EmptyCage[B]()
}
case EmptyCage() => EmptyCage[B]()
}
override def map[A, B](fa: Cage[A])
(f: (A) => B): Cage[B] = CageFunctor.map(fa)(f)
}
HOW WOULD YOU USE IT?
val partialShoot = Cage(PiranhaPlant()) <*> Cage((shoot _).curried)
val optCoin = Cage(Fireball()) <*> partialShoot
//optCoin: Cage[Coin] = FullCage(Coin())
val optCoin = EmptyCage[Fireball]() <*> partialShoot
//optCoin: Cage[Coin] = EmptyCage[Coin]()
WHAT HAVE WE DONE?
Taken a function that takes two values.
Turned it into a function that takes two values in a context.
TESTING THE LAWS
import org.scalacheck.Arbitrary
import org.specs2.scalaz.Spec
import scalaz.Equal
import scalaz.scalacheck.ScalazProperties
class CageApplySpec extends Spec {
implicit val abrCage = Arbitrary[Cage[Int]] {
for {
ns <- Arbitrary.arbInt.arbitrary
} yield Cage(ns)
}
implicit val arbCageIntToInt = Arbitrary[Cage[Int => Int]] {
for{
multi <- Arbitrary.arbInt.arbitrary
} yield Cage((x:Int) => x * multi)
}
implicit val cageEqual = Equal.equal[Cage[Int]]((a, b) => a == b)
checkAll(ScalazProperties.apply.laws[Cage])
}
OPTION APPLY: OPTIONINSTANCES
package scalaz
package std
override def ap[A, B](fa: => Option[A])
(f: => Option[A => B]) = f match {
case Some(f) => fa match {
case Some(x) => Some(f(x))
case None => None
}
case None => None
}
SHOOT THAT PIRANHA PLANT
import scalaz.std.option._
val partialShoot =
Option(PiranhaPlant()) <*> Option((shoot _).curried)
val optCoin = Option(Fireball()) <*> partialShoot
//optCoin: Option[Coin] = Some(Coin())
SOME NICER SYNTAX
import scalaz.std.option._
import scalaz.syntax.apply._
^(Option(PiranhaPlant()), Option(Fireball()))(shoot)
//res69: Option[Coin] = Some(Coin())
import scalaz.Apply
Apply[Option]
.lift2(shoot)(Option(PiranhaPlant()), Option(Fireball()))
//res70: Option[Coin] = Some(Coin())
LIST AS AN APPLY CONTEXT
val partial = List(PiranhaPlant(), PiranhaPlant(),
PiranhaPlant()) <*> List((shoot _).curried)
List(Fireball()) <*> partial
//res23: List[Coin] = List(Coin(), Coin(), Coin())
DISJUNCTION AS AN APPLY
/.right[String, Goomba](Goomba()) <*>
/.right[String, Goomba => Coin]((_:Goomba) => Coin())
//res: scalaz./[String,Coin] = /-(Coin())
Apply lets you take a function that takes values and turn it
into a function that takes values in a context.
Write the code once and reuse it in the context you need
REMEMBER THE THREE POINTS?
Abstraction: Apply is a abstract concept
Generalization: There is a set of objects that implement
the Apply trait
Context: How the funciton is used depends on the Apply
Specialization we are using
.
WORLD 1-3
Applicative
KOOPA PARATROOPA
HAS TO BE:
1. Koopa Paratroopa shot to a Koopa Troopa
2. Koopa Troopa is shot to a Shell
3. Shell is shot to a Coin
.
THE CODE
case class KoopaParatroopa()
case class KoopaTroopa()
case class Shell()
case class Coin()
case class Fireball()
def shootKP(fb: Fireball, kt:KoopaParatroopa) = KoopaTroopa()
def shootKT(fb: Fireball, kt:KoopaTroopa) = Shell()
def shootS(fb: Fireball, kt:Shell) = Coin()
val cagedKoopa = ^(Cage(Fireball()),
Cage(KoopaParatroopa()))(shootKP)
val cagedShell = ^(Cage(Fireball()), cagedKoopa)(shootKT)
val cagedCoin = ^(Cage(Fireball()), cagedShell)(shootS)
//cagedCoin: Cage[Coin] = FullCage(Coin())
APPLICATIVE
trait Applicative[F[_]] extends Apply[F] { self =>
////
def point[A](a: => A): F[A]
...
}
implicit object CageApplicative extends Applicative[Cage] {
override def ap[A, B](fa: => Cage[A])
(fab: => Cage[(A) => B]): Cage[B] = fab match {
case FullCage(f) => fa match {
case FullCage(x) => FullCage(f(x))
case EmptyCage() => EmptyCage[B]()
}
case EmptyCage() => EmptyCage[B]()
}
override def point[A](a: => A): Cage[A] = Cage(a)
}
We no longer need to define map
override def map[A, B](fa: F[A])(f: A => B): F[B] =
ap(fa)(point(f))
USING APPLICATIVE
import scalaz.syntax.applicative._
val cagedKoopa = ^(Fireball().point[Cage],
KoopaParatroopa().point[Cage])(shootKP)
val cagedShell = ^(Fireball().point[Cage], cagedKoopa)(shootKT)
val cagedCoin = ^(Fireball().point[Cage], cagedShell)(shootS)
//cagedCoin: Cage[Coin] = FullCage(Coin())
SAME CODE DIFFERENT CONTEXT
val cagedKoopa = ^(Fireball().point[List],
KoopaParatroopa().point[List])(shootKP)
val cagedShell = ^(Fireball().point[List], cagedKoopa)(shootKT)
val cagedCoin = ^(Fireball().point[List], cagedShell)(shootS)
//cagedCoin: List[Coin] = List(Coin())
REMEMBER
1. Abstraction: The Applicative
2. Generalisation: The Applicative trait
3. The context: Different behaviours for the same code
.
WORLD 1-4
Monad
BOWSER
THE RULES
Mario can hit Bowser
Bowser can hit Mario
Mario dies if at any point hits on Mario > hits on Bowser + 2
FIRST TRY
case class Hits(mario:Int, bowser:Int)
def hitBowser(hits: Hits) = hits.copy(bowser = hits.bowser + 1)
def hitMario(hits: Hits) = hits.copy(mario = hits.mario + 1)
def marioWins = hitMario _ andThen hitBowser
andThen hitBowser andThen hitBowser
marioWins(Hits(0,0))
//Hits = Hits(1,3)
HOW ABOUT THIS?
def marioWins = hitMario _ andThen hitMario andThen
hitMario andThen hitBowser andThen
hitBowser andThen hitBowser
marioWins(Hits(0,0))
//hits = Hits(3,3)
marioWins(Hits(3,0))
//marioWins(Hits(6,3))
Mario should have died
FAILING THE COMPUTATION?
Hits => Cage[Hits]
def hitMario2(hits: Hits):Cage[Hits] = hits match {
case ko:Hits if ko.mario + 1 - ko.bowser > 2 => EmptyCage[Hits]()
case Hits(mario, bowser) => Cage(Hits(mario + 1, bowser))
}
def hitBowser2(hits: Hits):Cage[Hits] = hits match {
case ko:Hits if ko.mario + 1- ko.bowser > 2 => EmptyCage[Hits]()
case Hits(mario, bowser) => Cage(Hits(mario, bowser + 1))
}
What's the problem?
THE HITS ARE TRAPPED IN THE CAGE!!
MONAD
MONAD
trait Bind[F[_]] extends Apply[F] { self =>
def bind[A, B](fa: F[A])(f: A => F[B]): F[B]
override def ap[A, B](fa: => F[A])(f: => F[A => B]): F[B] = {
lazy val fa0 = fa
bind(f)(map(fa0))
}
...
}
trait Monad[F[_]] extends Applicative[F] with Bind[F] { self =>
...
override def map[A,B](fa: F[A])(f: A => B) = bind(fa)(a => point(f(a)))
...
}
Define point and bind and we get map and ap for free
CAGE MONAD
implicit object CageMonad extends Monad[Cage]{
override def bind[A, B](fa: Cage[A])(f: (A) => Cage[B]):
Cage[B] = fa match {
case FullCage(a) => f(a)
case EmptyCage() => EmptyCage[B]()
}
override def point[A](a: => A): Cage[A] = Cage(a)
}
BINDOPS
final class BindOps[F[_],A] private[syntax](val self: F[A])
(implicit val F: Bind[F]) extends Ops[F[A]] {
...
def flatMap[B](f: A => F[B]) = F.bind(self)(f)
def >>=[B](f: A => F[B]) = F.bind(self)(f)
...
}
trait ToBindOps extends ToBindOps0 with ToApplyOps {
implicit def ToBindOps[F[_],A](v: F[A])(implicit F0: Bind[F]) =
new BindOps[F,A](v)
}
NOW
import scalaz.syntax.monad._
Cage(Hits(0,0)) >>= hitMario2 >>= hitMario2 >>=
hitMario2 >>= hitBowser2 >>= hitBowser2 >>= hitBowser2
//Cage[Hits] = EmptyCage()
Cage(Hits(0,2)) >>= hitMario2 >>= hitMario2 >>=
hitMario2 >>= hitBowser2 >>= hitBowser2 >>= hitBowser2
//Cage[Hits] = FullCage(Hits(3,5))
FOR COMPREHENSION FLAT MAP
val x = for {
r1 <- Cage(Hits(0,0))
r2 <- hitMario2(r1)
r3 <- hitMario2(r2)
r4 <- hitMario2(r3)
r5 <- hitBowser2(r4)
r6 <- hitBowser2(r5)
result <- hitBowser2(r6)
} yield result
OTHER MONADS
def addTwo(x:Int) = Some(x + 2)
1.some >>= addTwo
//addTwo: (x: Int)List[Int]
def addTwo(x:Int) = List(x + 2)
List(1,2,3) >>= addTwo
//List[Int] = List(3, 4, 5)
Reader Monad
Writer Monad
State Monad
MONAD LAWS
Inherit the laws from Bind and Applicative
Right Identity
Left Identity
HANG ON I CAN'T REUSE THESE
FUNCTIONS
def hitMario3[F[_]](hits: Hits)(implicit F0: Monad[F])
:F[Hits] = hits match {
case ko:Hits if ko.mario + 1 - ko.bowser > 2 =>
F0.point(null: Hits)
case Hits(mario, bowser) =>
F0.point(Hits(mario + 1, bowser))
}
def hitBowser3[F[_]](hits: Hits)(implicit F0: Monad[F])
:F[Hits] = hits match {
case ko:Hits if ko.mario + 1- ko.bowser > 2 =>
F0.point(null: Hits)
case Hits(mario, bowser) =>
F0.point(Hits(mario, bowser + 1))
}
Cage(Hits(1,2)) >>= hitMario3[Cage]
//Cage[Hits] = FullCage(Hits(2,2))
Cage(Hits(1,2)) >>= hitBowser3[Cage]
//Cage[Hits] = FullCage(Hits(1,3))
MONAD
Lets us call a function that takes a value and returns a value
in a context with a value in a context.
REMEMBER
1. Abstraction: The Monad
2. Generalisation: The Monad trait
3. The context: Different behaviours for the same code
SUMMARY
Functor
Apply
Applicative
Monad
def map[A, B](fa: F[A])(f: A => B): F[B]
def ap[A,B](fa: => F[A])
(f: => F[A => B]): F[B]
def point[A](a: => A): F[A]
def bind[A, B](fa: F[A]) (f: A => F[B]): F[B]
REFERENCES
Learn you a Haskell for Greater Good
Leaning Scalaz
Functional Programming in Scala
Bartosz Blog
http://learnyouahaskell.com/
http://eed3si9n.com/learning-scalaz/
https://www.manning.com/books/functional-
programming-in-scala
http://bartoszmilewski.com/2014/10/28/category-theory-
for-programmers-the-preface/
.

Weitere ähnliche Inhalte

Was ist angesagt?

Functional Patterns in Domain Modeling
Functional Patterns in Domain ModelingFunctional Patterns in Domain Modeling
Functional Patterns in Domain ModelingDebasish Ghosh
 
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaExploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaJorge Vásquez
 
Taking your side effects aside
Taking your side effects asideTaking your side effects aside
Taking your side effects aside💡 Tomasz Kogut
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...Philip Schwarz
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsPhilip Schwarz
 
ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022Alexander Ioffe
 
Comparing JVM Web Frameworks - February 2014
Comparing JVM Web Frameworks - February 2014Comparing JVM Web Frameworks - February 2014
Comparing JVM Web Frameworks - February 2014Matt Raible
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them AllJohn De Goes
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaWiem Zine Elabidine
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modelingMario Fusco
 
Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Philip Schwarz
 
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldFunctional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldJorge Vásquez
 
A Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOA Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOJorge Vásquez
 
Running Free with the Monads
Running Free with the MonadsRunning Free with the Monads
Running Free with the Monadskenbot
 
The Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldThe Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldPhilip Schwarz
 

Was ist angesagt? (20)

Functional Patterns in Domain Modeling
Functional Patterns in Domain ModelingFunctional Patterns in Domain Modeling
Functional Patterns in Domain Modeling
 
Applicative style programming
Applicative style programmingApplicative style programming
Applicative style programming
 
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaExploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in Scala
 
Taking your side effects aside
Taking your side effects asideTaking your side effects aside
Taking your side effects aside
 
Applicative Functor
Applicative FunctorApplicative Functor
Applicative Functor
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
 
ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022
 
Comparing JVM Web Frameworks - February 2014
Comparing JVM Web Frameworks - February 2014Comparing JVM Web Frameworks - February 2014
Comparing JVM Web Frameworks - February 2014
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them All
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in Scala
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
Java 8 Workshop
Java 8 WorkshopJava 8 Workshop
Java 8 Workshop
 
Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Sequence and Traverse - Part 2
Sequence and Traverse - Part 2
 
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldFunctional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorld
 
A Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOA Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIO
 
Java interface
Java interfaceJava interface
Java interface
 
Running Free with the Monads
Running Free with the MonadsRunning Free with the Monads
Running Free with the Monads
 
The Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldThe Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and Fold
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 

Ähnlich wie Functor, Apply, Applicative And Monad

Things about Functional JavaScript
Things about Functional JavaScriptThings about Functional JavaScript
Things about Functional JavaScriptChengHui Weng
 
Столпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай МозговойСтолпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай МозговойSigma Software
 
Contravariant functors in scala
Contravariant functors in scalaContravariant functors in scala
Contravariant functors in scalaPiotr Paradziński
 
Journey of a C# developer into Javascript
Journey of a C# developer into JavascriptJourney of a C# developer into Javascript
Journey of a C# developer into JavascriptMassimo Franciosa
 
Writing DSL with Applicative Functors
Writing DSL with Applicative FunctorsWriting DSL with Applicative Functors
Writing DSL with Applicative FunctorsDavid Galichet
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme SwiftMovel
 
Talk - Query monad
Talk - Query monad Talk - Query monad
Talk - Query monad Fabernovel
 
Javascript And J Query
Javascript And J QueryJavascript And J Query
Javascript And J Queryitsarsalan
 
Cocoa Design Patterns in Swift
Cocoa Design Patterns in SwiftCocoa Design Patterns in Swift
Cocoa Design Patterns in SwiftMichele Titolo
 
Introduction to Client-Side Javascript
Introduction to Client-Side JavascriptIntroduction to Client-Side Javascript
Introduction to Client-Side JavascriptJulie Iskander
 
K is for Kotlin
K is for KotlinK is for Kotlin
K is for KotlinTechMagic
 
Writer Monad for logging execution of functions
Writer Monad for logging execution of functionsWriter Monad for logging execution of functions
Writer Monad for logging execution of functionsPhilip Schwarz
 
SystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummarySystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummaryAmal Khailtash
 
EcmaScript unchained
EcmaScript unchainedEcmaScript unchained
EcmaScript unchainedEduard Tomàs
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scalapramode_ce
 

Ähnlich wie Functor, Apply, Applicative And Monad (20)

Things about Functional JavaScript
Things about Functional JavaScriptThings about Functional JavaScript
Things about Functional JavaScript
 
Столпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай МозговойСтолпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай Мозговой
 
Contravariant functors in scala
Contravariant functors in scalaContravariant functors in scala
Contravariant functors in scala
 
Journey of a C# developer into Javascript
Journey of a C# developer into JavascriptJourney of a C# developer into Javascript
Journey of a C# developer into Javascript
 
Coding in Style
Coding in StyleCoding in Style
Coding in Style
 
Writing DSL with Applicative Functors
Writing DSL with Applicative FunctorsWriting DSL with Applicative Functors
Writing DSL with Applicative Functors
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme Swift
 
Talk - Query monad
Talk - Query monad Talk - Query monad
Talk - Query monad
 
Javascript And J Query
Javascript And J QueryJavascript And J Query
Javascript And J Query
 
Cocoa Design Patterns in Swift
Cocoa Design Patterns in SwiftCocoa Design Patterns in Swift
Cocoa Design Patterns in Swift
 
Introduction to Client-Side Javascript
Introduction to Client-Side JavascriptIntroduction to Client-Side Javascript
Introduction to Client-Side Javascript
 
Scala for curious
Scala for curiousScala for curious
Scala for curious
 
K is for Kotlin
K is for KotlinK is for Kotlin
K is for Kotlin
 
Writer Monad for logging execution of functions
Writer Monad for logging execution of functionsWriter Monad for logging execution of functions
Writer Monad for logging execution of functions
 
SystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummarySystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features Summary
 
Scala ntnu
Scala ntnuScala ntnu
Scala ntnu
 
EcmaScript unchained
EcmaScript unchainedEcmaScript unchained
EcmaScript unchained
 
Joy of scala
Joy of scalaJoy of scala
Joy of scala
 
Advanced JavaScript
Advanced JavaScript Advanced JavaScript
Advanced JavaScript
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scala
 

Kürzlich hochgeladen

Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 

Kürzlich hochgeladen (20)

Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 

Functor, Apply, Applicative And Monad

  • 3. SO LET'S TRY INSTEAD ...
  • 4. .
  • 5. WHY SHOULD YOU CARE? How do Functors, Apply, Applicative and Monad help you achieve early and continuous delivery of software?
  • 7. IF A PIZZA COSTS $16 AND YOU BUY TWO HOW MUCH DO YOU SPEND?
  • 8. A MARIO KART COSTS $20 PER DAY TO RENT. HOW MUCH DOES IT COST TO RENT FOR TWO DAYS?
  • 9. DON'T JUST THINK ABOUT THE MATHS Think about the process you are going through before you get to the maths. What information are you keeping and what information are you dropping?
  • 10. .
  • 11. ABSTRACTION Abstraction is an emphasis on the idea, qualities and properties rather than the particulars The importance of abstraction is derived from its ability to hide irrelevant details It doesn't matter if its pizza, mario carts or anything else we take the cost and muliply it by some factor.
  • 12. WHAT IS THE REALATION SHIP BETWEEN A POLOGON: A 3 sided triangle A 4 sided quadrilateral
  • 13. WHAT HAS AM × AN = AM+N GOT IN COMMON WITH: a2 × a3 = (a × a) × (a × a × a) = a5 a3 × a4 = (a × a × a) × (a × a × a × a) = a7
  • 14. .
  • 15. GENERALIZATION Relationship that holds between all members of some set of objects
  • 16. IS A MILE A LONG WAY?
  • 17. IS A YEAR A LARGE AMOUNT OF TIME?
  • 18. .
  • 19. IT ALL DEPENDS ON CONTEXT A mile is along way if you are an Ant but not if you are flying in an aeroplane. A year is a long time for a Mayfly that lives for only 5 minutes. But in geological time it's insignificant.
  • 21. WHAT IS FUNCTIONAL PROGRAMMING? Construct our programs using only pure functions. Pure functions have no side effects.
  • 22. WHY IS A FUNCTION LIKE A PIPE? Some thing goes into one end and something else comes out the other end
  • 23. Simple pipes simple can be joined together to form complex systems?
  • 24. WHAT'S SO GOOD ABOUT NO SIDE EFFECTS? It makes it easier to reason about what's going on
  • 25. IT'S IMPORTANT THAT FUNCTIONS LIKE PIPES DON'T LEAK
  • 28. HOW TO DEFEAT A GOOMBA Stomp it and it turns into a coin case class Coin() case class Goomba() def stomp(g:Goomba) = Coin() The function stomp is our pipe, that transforms from a Goomba to a Coin.
  • 29. LUIGIS VACUUM TO COLLECT GOOMBAS class Vacuum { def collect(g:Goomba) = stomp(s) } val vacuum = new Vacuum() val goomba = new Goomba() vacuum.collect(goomba) //Coin()
  • 30. WHAT HAPPENS WHEN THE GOOMBA ESCAPES THE SUCTION? val vacuum = new Vacuum() vacuum.collect(null)
  • 31. .
  • 32. CHECK FOR NULLS class Vacuum { def collect(s:Goomba) = if (s == null) null else stomp(s) } But then the calling class runs the risk of NullPointer exceptions.
  • 33. There must be a better way
  • 35. sealed trait Cage[T] case class FullCage[T](value: T) extends Cage[T] case class EmptyCage[T]() extends Cage[T] object Cage { def apply[T](x: T):Cage[T] = if (x == null) EmptyCage[T]() else FullCage(x) } class Vacuum { def collect(c:Cage[Goomba]):Cage[Coin] = c match { case EmptyCage() => EmptyCage[Coin]() case FullCage(s) => FullCage(stomp(s)) } } val vac = new Vacuum() vac.collect(Cage(Goomba())) //FullCage[Coin](Coin()) vac.collect(Cage(null)) //EmptyCage[Coin]()
  • 36. .
  • 37. CAN WE GENERALIZE THE VACUUM CLASS?
  • 38. WHY LIMIT OURSELF TO JUST STOMPING GOOMBAS IN THE CAGE? class Vacuum { def collect[A,B](c:Cage[A], f:A => B):Cage[B] = c match { case EmptyCage() => EmptyCage[B]() case FullCage(s) => FullCage(f(s)) } }
  • 39. Turn it into a trait trait Collector { def collect[A,B](c:Cage[A], f:A => B):Cage[B] } class Vacuum extends Collector { def collect[A,B](c:Cage[A], f:A => B):Cage[B] = c match { case EmptyCage() => EmptyCage[B]() case FullCage(s) => FullCage(f(s)) } }
  • 40. Parameterise the trait trait Collector[F[_]] { def collect[A,B](c:F[A], f:A => B): F[B] } object Vacuum extends Collector[Cage] { def collect[A,B](c:Cage[A], f:A => B):Cage[B] = c match { case EmptyCage() => EmptyCage[B]() case FullCage(s) => FullCage(f(s)) } }
  • 41. .
  • 42. THE FUNCTOR A functor is basically for things that can be mapped over.
  • 43. THE FUNCTOR DEFINITION IN SCALAZ package scalaz trait Functor[F[_]] extends InvariantFunctor[F] { self => ... /** Lift `f` into `F` and apply to `F[A]`. */ def map[A, B](fa: F[A])(f: A => B): F[B] ... }
  • 44. HOW DO YOU USE IT? object CageFunctor extends Functor[Cage] { def map[A,B](c:Cage[A])(f:A => B):Cage[B] = c match { case EmptyCage() => EmptyCage[B]() case FullCage(s) => FullCage(f(s)) } } CageFunctor.map(Cage(Gummba()))(stomp)
  • 45. IS THERE A BETTER WAY?
  • 46. .
  • 47. TYPE CLASSES IN 60 SECONDS
  • 48. WHY? Extend existing classes Without inheritance Without altering original source Keeps concerns seperate
  • 49. HOW? 3 COMPONENTS 1. The type class 2. Instances for particular types 3. Interface methods for the api
  • 50. THE TYPE CLASS Provide a generic type of what we want to implement. trait ProtoBuffWriter[A] { def write(value: A): Array[Byte] }
  • 51. TYPE CLASS INSTANCES Provide implementations for the types we care about. Create concrete implementations of the type class and mark them as implicit. object DefaultProtoBuffWriters { implicit val coinWriter = ProtoBuffWriter[Coin] { .... } implicit val goombaWriter = ProtoBuffWriter[Goomba] { .... } // etc ... }
  • 52. INTERFACES What is exposed to clients. Generic methods that accept instances of the type class as implicit params. TWO WAYS OF DOING IT
  • 53. INTERFACE OBJECTS All methods in a singleton. object ProtoBuff { def toProtoBuff[A](value: A) (implicit writer: ProtoBuffWriter[A]): Array[Byte] { writer.write(value) } } import DefaultProtoBuffWriters._ val protoBuff: Array[Byte] = ProtoBuff.toProtoBuff(Coin())
  • 54. INTERFACE SYNTAX Pimp existing types with interface methods. object ProtoBuffSyntax { implicit class ProtoBuffWriter[A](value: A) { def toProtoBuff(implicit writer: ProtoBuffWriter[A]) : Array[Byte] = { writer.write(value) } } } import DefaultProtoBuffWriters._ import ProtBuffSyntax._ val protoBuff: Array[Byte] = Coin().toProtoBuff
  • 55. WHAT ABOUT SCALAZ? Pimp existing types Uses the Type classes in Ops classes Ops classes use the Type class and provide more methods import scala.language.implicitConversions sealed trait ToProtoBuffWriterOps { implicit def ToProtoBuffWriterOps[A](v: A) (implicit F: ProtoBuffWriter[A]) = new ProtoBuffWriterOps(v) } object protoBuffWriter extends ToProtoBuffWriterOps import sun.misc.BASE64Encoder //for example only class ProtoBuffWriterOps[A](val self: A) (implicit val F: ProtoBuffWriter[A]) { def write(value: A) = F.write(value) def writeBase64(value: A) = new BASE64Encoder().encodeBuffer(write(value)) }
  • 56. !!WARNING!! Implicits like warp pipes can be dangerous
  • 57. SCALAZ FUNCTOR SYNTAX: TOFUNCTOROPS scalaz.syntax.FunctorSyntax.scala trait ToFunctorOps extends ToFunctorOps0 with ToInvariantFunctorOps { implicit def ToFunctorOps[F[_],A](v: F[A])(implicit F0: Functor[F]) = new FunctorOps[F,A](v) ... } Given a F[A] and a implicit Functor[F] in scope add all the FunctorOps to F[A]
  • 58. SCALAZ FUNCTOR SYNTAX: FUNCTOROPS scalaz.syntax.FunctorSyntax.scala final class FunctorOps[F[_],A] private[syntax] (val self: F[A])(implicit val F: Functor[F]) extends Ops[F[A]] { ... final def map[B](f: A => B): F[B] = F.map(self)(f) ... } Given a F[A] and a implicit Functor[F] in scope delegate the map method to the Functor[F] in scope
  • 59. FINALLY scalaz.syntax package object extends Syntaxes trait Syntaxes { object functor extends ToFunctorOps } import scalaz.syntax.functor
  • 60. CAGE FUNCTOR AGAIN scalaz.syntax.FunctorSyntax.scala import scalaz.Functor implicit object CageFunctor extends Functor[Cage] { def map[A,B](c:Cage[A])(f:A => B):Cage[B] = c match { case EmptyCage() => EmptyCage[B]() case FullCage(s) => FullCage(f(s)) } } import scalaz.syntax.functor Cage(Goomba()).map(stomp)
  • 61. THE FUNCTOR LAWS Mapping preserves identity If we map the id function over a functor, the functor that we get back should be the same as the original functor Mapping respects composition Composing two functions and then mapping the resulting function over a functor should be the same as first mapping one function over the functor and then mapping the other one
  • 62. DOES YOUR FUNCTOR BREAK LAWS? import org.scalacheck.Arbitrary import org.specs2.scalaz.Spec import scalaz.Equal import scalaz.scalacheck.ScalazProperties class CageFunctorSpec extends Spec { implicit val abrCage = Arbitrary[Cage[Int]] { for { ns <- Arbitrary.arbInt.arbitrary } yield Cage(ns) } implicit val cageEqual = Equal.equal[Cage[Int]]((a, b) => a == b) checkAll(ScalazProperties.functor.laws[Cage]) } val scalazVersion = "7.1.3" libraryDependencies ++= Seq( "org.scalaz" %% "scalaz-core" % scalazVersion, "org.specs2" %% "specs2-core" % "2.4" % "test", "org.typelevel" %% "scalaz-specs2" % "0.3.0" % "test" )
  • 63. REMEMBER THE THREE POINTS? Abstraction: Functor is a abstract concept Generalization: There is a set of objects that can be mapped over What about the context?
  • 64. CONTEXT Context is the environment the function is applied in.
  • 65.
  • 67. SCALA.OPTION sealed abstract class Option[+A] extends Product with Serializable { ... final def map[B](f: A => B): Option[B] = if (isEmpty) None else Some(f(this.get)) ... } Scalaz provides implicits to convert Option to a Functor trait import scalaz.std.option._ import scalaz.std.anyVal._ checkAll(ScalazProperties.functor.laws[Option]) Option is context for a computation that might fail
  • 68. LIST ARE ALSO FUNCTORS sealed abstract class List[+A] { .... final def map[B](f: (A) ⇒ B): List[B] ... } Scalaz provides implicits to convert List to a Functor trait import scalaz.std.list._ import scalaz.std.anyVal._ import org.specs2.scalaz.Spec import scalaz.scalacheck.ScalazProperties class ListFunctorSpec extends Spec { checkAll(ScalazProperties.functor.laws[List]) } If 6 is deterministic and having one value. The List context such as List(1,10,3,4) can be thought of as having multipule values at once. Or no values if empty
  • 69. DISJUNCTIONS ARE FUNCTORS import org.specs2.scalaz.Spec import scalaz.scalacheck.ScalazProperties class ListFunctorSpec extends Spec { implicit val abrStringIntEither = Arbitrary[/[String, Int]] { for { ns <- Arbitrary.arbInt.arbitrary } yield /-(ns) } implicit val disjuncEqual = Equal.equal[/[String, Int]]((a, b) => { (a,b) match { case(-/(l1), -/(l2)) => l1 == l2 case(/-(r1), /-(r2)) => r1 == r2 case _ => false } }) //left type param is fixed checkAll(ScalazProperties.functor.laws[({type λ[α] = /[String, α]})#λ]) }
  • 70. SO WHY IS THIS SO HANDY?
  • 71. ORDINARY FUNCTIONS ARE SIMPLER TO: read write use reason about
  • 72. FUNCTIONS IN A CONTEXT HAVE USEFUL PROPERTIES Functors let us write ordinary functions Then promote those functions into every context that might need that code As new contexts arise we just define new functors to promote our ordinary code to work in those contexts.
  • 73. ///Ordinary function def stomp(g:Goomba) = g.stomp() ///The context sealed trait Cage[T] case class FullCage[T](value: T) extends Cage[T] case class EmptyCage[T]() extends Cage[T] object Cage { def apply[T](x: T):Cage[T] = if (x == null) EmptyCage[T]() else FullCage(x) } ///Promote into context import scalaz.Functor implicit object CageFunctor extends Functor[Cage] { def map[A,B](c:Cage[A])(f:A => B):Cage[B] = c match { case EmptyCage() => EmptyCage[B]() case FullCage(s) => FullCage(f(s)) } } ///use import scalaz.syntax.functor Cage(Goomba()).map(stomp)
  • 74. .
  • 77. PIRANHA PLANT case class Coin() case class Fireball() case class PiranhaPlant() def shoot(plant:PiranhaPlant, fireball:Fireball): Coin = Coin()
  • 78. THE PLANT IS GENERATED FROM A UNRELIABLE SOURCE Wrap the plant in a Cage and map over it? Cage(PiranhaPlant()).map(shoot _) <console>:31: error: type mismatch; found : (PiranhaPlant, Fireball) => Coin required: PiranhaPlant => ? Cage(PiranhaPlant()).map(shoot _) </console>
  • 80. CURRING IS PARTIAL APPLICATION Translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument (shoot _).curried //res41: PiranhaPlant => (Fireball => Coin) = <function1> </function1>
  • 81. MAP THE CURRIED SHOOT FUNCTION Cage(PiranhaPlant()) map {shoot _}.curried //Cage[Fireball => Coin] = ...
  • 82. WHAT IF THE FIREBALL PARAMETER GENERATION IS IN A CONTEXT? Functor only support mapping functions over functor def map[A, B](fa: F[A])(f: A => B): F[B] We need to map function in a functor over a value in a functor
  • 83. APPLY package scalaz trait Apply[F[_]] extends Functor[F] { self => //// def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B] ... } package scalaz package syntax final class ApplyOps[F[_],A] private[syntax](val self: F[A]) (implicit val F: Apply[F]) extends Ops[F[A]] { final def <*>[B](f: F[A => B]): F[B] = F.ap(self)(f) ... } trait ToApplyOps extends ToApplyOps0 with ToFunctorOps { implicit def ToApplyOps[F[_],A](v: F[A])(implicit F0: Apply[F]) = new ApplyOps[F,A](v) ... }
  • 84. WHAT WOULD OUR VACUUM LOOK LIKE? implicit object CageApply extends Apply[Cage]{ override def ap[A, B](fa: => Cage[A]) (fab: => Cage[(A) => B]): Cage[B] = fab match { case FullCage(f) => fa match { case FullCage(x) => FullCage(f(x)) case EmptyCage() => EmptyCage[B]() } case EmptyCage() => EmptyCage[B]() } override def map[A, B](fa: Cage[A]) (f: (A) => B): Cage[B] = CageFunctor.map(fa)(f) }
  • 85. HOW WOULD YOU USE IT? val partialShoot = Cage(PiranhaPlant()) <*> Cage((shoot _).curried) val optCoin = Cage(Fireball()) <*> partialShoot //optCoin: Cage[Coin] = FullCage(Coin()) val optCoin = EmptyCage[Fireball]() <*> partialShoot //optCoin: Cage[Coin] = EmptyCage[Coin]()
  • 86. WHAT HAVE WE DONE? Taken a function that takes two values. Turned it into a function that takes two values in a context.
  • 87. TESTING THE LAWS import org.scalacheck.Arbitrary import org.specs2.scalaz.Spec import scalaz.Equal import scalaz.scalacheck.ScalazProperties class CageApplySpec extends Spec { implicit val abrCage = Arbitrary[Cage[Int]] { for { ns <- Arbitrary.arbInt.arbitrary } yield Cage(ns) } implicit val arbCageIntToInt = Arbitrary[Cage[Int => Int]] { for{ multi <- Arbitrary.arbInt.arbitrary } yield Cage((x:Int) => x * multi) } implicit val cageEqual = Equal.equal[Cage[Int]]((a, b) => a == b) checkAll(ScalazProperties.apply.laws[Cage]) }
  • 88. OPTION APPLY: OPTIONINSTANCES package scalaz package std override def ap[A, B](fa: => Option[A]) (f: => Option[A => B]) = f match { case Some(f) => fa match { case Some(x) => Some(f(x)) case None => None } case None => None }
  • 89. SHOOT THAT PIRANHA PLANT import scalaz.std.option._ val partialShoot = Option(PiranhaPlant()) <*> Option((shoot _).curried) val optCoin = Option(Fireball()) <*> partialShoot //optCoin: Option[Coin] = Some(Coin())
  • 90. SOME NICER SYNTAX import scalaz.std.option._ import scalaz.syntax.apply._ ^(Option(PiranhaPlant()), Option(Fireball()))(shoot) //res69: Option[Coin] = Some(Coin()) import scalaz.Apply Apply[Option] .lift2(shoot)(Option(PiranhaPlant()), Option(Fireball())) //res70: Option[Coin] = Some(Coin())
  • 91. LIST AS AN APPLY CONTEXT val partial = List(PiranhaPlant(), PiranhaPlant(), PiranhaPlant()) <*> List((shoot _).curried) List(Fireball()) <*> partial //res23: List[Coin] = List(Coin(), Coin(), Coin())
  • 92. DISJUNCTION AS AN APPLY /.right[String, Goomba](Goomba()) <*> /.right[String, Goomba => Coin]((_:Goomba) => Coin()) //res: scalaz./[String,Coin] = /-(Coin())
  • 93. Apply lets you take a function that takes values and turn it into a function that takes values in a context. Write the code once and reuse it in the context you need
  • 94. REMEMBER THE THREE POINTS? Abstraction: Apply is a abstract concept Generalization: There is a set of objects that implement the Apply trait Context: How the funciton is used depends on the Apply Specialization we are using
  • 95. .
  • 98. HAS TO BE: 1. Koopa Paratroopa shot to a Koopa Troopa 2. Koopa Troopa is shot to a Shell 3. Shell is shot to a Coin
  • 99. .
  • 100. THE CODE case class KoopaParatroopa() case class KoopaTroopa() case class Shell() case class Coin() case class Fireball() def shootKP(fb: Fireball, kt:KoopaParatroopa) = KoopaTroopa() def shootKT(fb: Fireball, kt:KoopaTroopa) = Shell() def shootS(fb: Fireball, kt:Shell) = Coin() val cagedKoopa = ^(Cage(Fireball()), Cage(KoopaParatroopa()))(shootKP) val cagedShell = ^(Cage(Fireball()), cagedKoopa)(shootKT) val cagedCoin = ^(Cage(Fireball()), cagedShell)(shootS) //cagedCoin: Cage[Coin] = FullCage(Coin())
  • 101. APPLICATIVE trait Applicative[F[_]] extends Apply[F] { self => //// def point[A](a: => A): F[A] ... } implicit object CageApplicative extends Applicative[Cage] { override def ap[A, B](fa: => Cage[A]) (fab: => Cage[(A) => B]): Cage[B] = fab match { case FullCage(f) => fa match { case FullCage(x) => FullCage(f(x)) case EmptyCage() => EmptyCage[B]() } case EmptyCage() => EmptyCage[B]() } override def point[A](a: => A): Cage[A] = Cage(a) } We no longer need to define map override def map[A, B](fa: F[A])(f: A => B): F[B] = ap(fa)(point(f))
  • 102. USING APPLICATIVE import scalaz.syntax.applicative._ val cagedKoopa = ^(Fireball().point[Cage], KoopaParatroopa().point[Cage])(shootKP) val cagedShell = ^(Fireball().point[Cage], cagedKoopa)(shootKT) val cagedCoin = ^(Fireball().point[Cage], cagedShell)(shootS) //cagedCoin: Cage[Coin] = FullCage(Coin())
  • 103. SAME CODE DIFFERENT CONTEXT val cagedKoopa = ^(Fireball().point[List], KoopaParatroopa().point[List])(shootKP) val cagedShell = ^(Fireball().point[List], cagedKoopa)(shootKT) val cagedCoin = ^(Fireball().point[List], cagedShell)(shootS) //cagedCoin: List[Coin] = List(Coin())
  • 104. REMEMBER 1. Abstraction: The Applicative 2. Generalisation: The Applicative trait 3. The context: Different behaviours for the same code
  • 105. .
  • 107. BOWSER
  • 108. THE RULES Mario can hit Bowser Bowser can hit Mario Mario dies if at any point hits on Mario > hits on Bowser + 2
  • 109. FIRST TRY case class Hits(mario:Int, bowser:Int) def hitBowser(hits: Hits) = hits.copy(bowser = hits.bowser + 1) def hitMario(hits: Hits) = hits.copy(mario = hits.mario + 1) def marioWins = hitMario _ andThen hitBowser andThen hitBowser andThen hitBowser marioWins(Hits(0,0)) //Hits = Hits(1,3)
  • 110. HOW ABOUT THIS? def marioWins = hitMario _ andThen hitMario andThen hitMario andThen hitBowser andThen hitBowser andThen hitBowser marioWins(Hits(0,0)) //hits = Hits(3,3) marioWins(Hits(3,0)) //marioWins(Hits(6,3)) Mario should have died
  • 111. FAILING THE COMPUTATION? Hits => Cage[Hits] def hitMario2(hits: Hits):Cage[Hits] = hits match { case ko:Hits if ko.mario + 1 - ko.bowser > 2 => EmptyCage[Hits]() case Hits(mario, bowser) => Cage(Hits(mario + 1, bowser)) } def hitBowser2(hits: Hits):Cage[Hits] = hits match { case ko:Hits if ko.mario + 1- ko.bowser > 2 => EmptyCage[Hits]() case Hits(mario, bowser) => Cage(Hits(mario, bowser + 1)) } What's the problem?
  • 112. THE HITS ARE TRAPPED IN THE CAGE!!
  • 113. MONAD
  • 114. MONAD trait Bind[F[_]] extends Apply[F] { self => def bind[A, B](fa: F[A])(f: A => F[B]): F[B] override def ap[A, B](fa: => F[A])(f: => F[A => B]): F[B] = { lazy val fa0 = fa bind(f)(map(fa0)) } ... } trait Monad[F[_]] extends Applicative[F] with Bind[F] { self => ... override def map[A,B](fa: F[A])(f: A => B) = bind(fa)(a => point(f(a))) ... } Define point and bind and we get map and ap for free
  • 115. CAGE MONAD implicit object CageMonad extends Monad[Cage]{ override def bind[A, B](fa: Cage[A])(f: (A) => Cage[B]): Cage[B] = fa match { case FullCage(a) => f(a) case EmptyCage() => EmptyCage[B]() } override def point[A](a: => A): Cage[A] = Cage(a) }
  • 116. BINDOPS final class BindOps[F[_],A] private[syntax](val self: F[A]) (implicit val F: Bind[F]) extends Ops[F[A]] { ... def flatMap[B](f: A => F[B]) = F.bind(self)(f) def >>=[B](f: A => F[B]) = F.bind(self)(f) ... } trait ToBindOps extends ToBindOps0 with ToApplyOps { implicit def ToBindOps[F[_],A](v: F[A])(implicit F0: Bind[F]) = new BindOps[F,A](v) }
  • 117. NOW import scalaz.syntax.monad._ Cage(Hits(0,0)) >>= hitMario2 >>= hitMario2 >>= hitMario2 >>= hitBowser2 >>= hitBowser2 >>= hitBowser2 //Cage[Hits] = EmptyCage() Cage(Hits(0,2)) >>= hitMario2 >>= hitMario2 >>= hitMario2 >>= hitBowser2 >>= hitBowser2 >>= hitBowser2 //Cage[Hits] = FullCage(Hits(3,5))
  • 118. FOR COMPREHENSION FLAT MAP val x = for { r1 <- Cage(Hits(0,0)) r2 <- hitMario2(r1) r3 <- hitMario2(r2) r4 <- hitMario2(r3) r5 <- hitBowser2(r4) r6 <- hitBowser2(r5) result <- hitBowser2(r6) } yield result
  • 119. OTHER MONADS def addTwo(x:Int) = Some(x + 2) 1.some >>= addTwo //addTwo: (x: Int)List[Int] def addTwo(x:Int) = List(x + 2) List(1,2,3) >>= addTwo //List[Int] = List(3, 4, 5) Reader Monad Writer Monad State Monad
  • 120. MONAD LAWS Inherit the laws from Bind and Applicative Right Identity Left Identity
  • 121. HANG ON I CAN'T REUSE THESE FUNCTIONS def hitMario3[F[_]](hits: Hits)(implicit F0: Monad[F]) :F[Hits] = hits match { case ko:Hits if ko.mario + 1 - ko.bowser > 2 => F0.point(null: Hits) case Hits(mario, bowser) => F0.point(Hits(mario + 1, bowser)) } def hitBowser3[F[_]](hits: Hits)(implicit F0: Monad[F]) :F[Hits] = hits match { case ko:Hits if ko.mario + 1- ko.bowser > 2 => F0.point(null: Hits) case Hits(mario, bowser) => F0.point(Hits(mario, bowser + 1)) } Cage(Hits(1,2)) >>= hitMario3[Cage] //Cage[Hits] = FullCage(Hits(2,2)) Cage(Hits(1,2)) >>= hitBowser3[Cage] //Cage[Hits] = FullCage(Hits(1,3))
  • 122. MONAD Lets us call a function that takes a value and returns a value in a context with a value in a context.
  • 123. REMEMBER 1. Abstraction: The Monad 2. Generalisation: The Monad trait 3. The context: Different behaviours for the same code
  • 124. SUMMARY Functor Apply Applicative Monad def map[A, B](fa: F[A])(f: A => B): F[B] def ap[A,B](fa: => F[A]) (f: => F[A => B]): F[B] def point[A](a: => A): F[A] def bind[A, B](fa: F[A]) (f: A => F[B]): F[B]
  • 125. REFERENCES Learn you a Haskell for Greater Good Leaning Scalaz Functional Programming in Scala Bartosz Blog http://learnyouahaskell.com/ http://eed3si9n.com/learning-scalaz/ https://www.manning.com/books/functional- programming-in-scala http://bartoszmilewski.com/2014/10/28/category-theory- for-programmers-the-preface/
  • 126. .