SlideShare a Scribd company logo
1 of 103
Download to read offline
[error] Exception encountered
[error] java.lang.StackOverflowError
WHY THE FREE MONAD ISN’T FREE
“Let’s just trampoline it and
add the Free Monad”
@kelleyrobinson
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson
“Let’s just trampoline it and
add the Free Monad”
Why The Free
Monad Isn’t Free
Kelley Robinson
Data & Infrastructure Engineer
Sharethrough
@kelleyrobinson
WHY THE FREE MONAD ISN’T FREE
- Monoids, Functors & Monads
- How to be “Free”
- Why & Why Not “Free”
- Alternatives
- Real World Applications
$
@kelleyrobinson
WHY THE FREE MONAD ISN’T FREE
github.com/robinske/monad-examples
WHY THE FREE MONAD ISN’T FREE
https://twitter.com/rickasaurus/status/705134684427128833
WHY THE FREE MONAD ISN’T FREE
Monoids
@kelleyrobinson
@kelleyrobinson
trait Monoid[A] {


def append(a: A, b: A): A


def identity: A

}
WHY THE FREE MONAD ISN'T FREE
Monoids
Image credit: deluxebattery.com
WHY THE FREE MONAD ISN'T FREE
Properties
Identity: "no-op" value
Associativity:
grouping doesn't matter
@kelleyrobinson
@kelleyrobinson
object StringConcat extends Monoid[String] {



def append(a: String, b: String): String = a + b



def identity: String = ""



}
@kelleyrobinson
object IntegerAddition extends Monoid[Int] {



def append(a: Int, b: Int): Int = a + b



def identity: Int = 0



}
@kelleyrobinson
object IntegerMultiplication extends Monoid[Int] {



def append(a: Int, b: Int): Int = a * b



def identity: Int = 1



}
@kelleyrobinson
object FunctionComposition /* extends Monoid[_=>_] */ {



def append[A, B, C](f1: A => B, f2: B => C): A => C =
(a: A) => f2(f1(a))



def identity[A]: A => A = (a: A) => a


}
@kelleyrobinson
object FunctionComposition /* extends Monoid[_=>_] */ {



def append[A, B, C](f1: A => B, f2: B => C): A => C =
(a: A) => f2(f1(a))



def identity[A]: A => A = (a: A) => a


}
WHY THE FREE MONAD ISN’T FREE
Functors
@kelleyrobinson
@kelleyrobinson
trait Functor[F[_]] {



def map[A, B](a: F[A])(fn: A => B): F[B]



}
WHY THE FREE MONAD ISN'T FREE
@kelleyrobinson
Properties
Identity: "no-op" value
Composition:
grouping doesn't matter
@kelleyrobinson
sealed trait Option[+A]

case class Some[A](a: A) extends Option[A]

case object None extends Option[Nothing]
object OptionFunctor extends Functor[Option] {



def map[A, B](a: Option[A])(fn: A => B): Option[B] =

a match {

case Some(something) => Some(fn(something))

case None => None

}

}
@kelleyrobinson
it("should follow the identity law") {

def identity[A](a: A): A = a

assert(map(Some("foo"))(identity) == Some("foo"))

}
@kelleyrobinson
it("should follow the composition law") {
val f: String => String = s => s + "a"

val g: String => String = s => s + "l"
val h: String => String = s => s + "a"
assert(
map(Some("sc"))(f andThen g andThen h) ==
map(map(map(Some("sc"))(f))(g))(h) ==
"scala"
)
}
Functors are Endofunctors**
**in Scala
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson
WHY THE FREE MONAD ISN’T FREE
Monads
@kelleyrobinson
"The term monad is a bit
vacuous if you are not a
mathematician. An alternative
term is computation builder."
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson http://stackoverflow.com/questions/44965/what-is-a-monad
@kelleyrobinson
trait Monad[M[_]] {


def pure[A](a: A): M[A]

def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]

}
@kelleyrobinson
sealed trait Option[+A]

case class Some[A](a: A) extends Option[A]

case object None extends Option[Nothing]



object OptionMonad extends Monad[Option] {



def pure[A](a: A): Option[A] = Some(a)



def flatMap[A, B](a: Option[A])(fn: A => Option[B]): Option[B] =

a match {

case Some(something) => fn(something)

case None => None

}

}
@kelleyrobinson
trait Monad[M[_]] {


def pure[A](a: A): M[A]

def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]

}
@kelleyrobinson
trait Monad[M[_]] {

def pure[A](a: A): M[A]

def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]



def map[A, B](a: M[A])(fn: A => B): M[B] = {

flatMap(a){ b: A => pure(fn(b)) }

}


}
@kelleyrobinson
trait Monad[M[_]] {
def pure[A](a: A): M[A]

def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]



def map[A, B](a: M[A])(fn: A => B): M[B] = {

flatMap(a){ b: A => pure(fn(b)) }

}

}
@kelleyrobinson
trait Monad[M[_]] {

def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]

def append[A, B, C]
(f1: A => M[B], f2: B => M[C]): A => M[C] = {
a: A =>

val bs: M[B] = f1(a)

val cs: M[C] = flatMap(bs) { b: B =>
f2(b)
}

cs

}


}
@kelleyrobinson
trait Monad[M[_]] {

def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]

def append[A, B, C]
(f1: A => M[B], f2: B => M[C]): A => M[C] = {
a: A =>

val bs: M[B] = f1(a)

val cs: M[C] = flatMap(bs) { b: B =>
f2(b)
}

cs

}


}
WHY THE FREE MONAD ISN'T FREE
Properties
Identity: "no-op" value
Composition:
grouping doesn't matter
@kelleyrobinson
WHY THE FREE MONAD ISN'T FREE
Compose functions
for values in a
context
Think: Lists, Options, Futures
@kelleyrobinson
trait Monad[M[_]]
extends Functor[M]
/* with Monoid[_=>M[_]] */ {


def pure[A](a: A): M[A]

def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]



def map[A, B](a: M[A])(fn: A => B): M[B]

def append[A, B, C](f1: A => M[B], f2: B => M[C]): A => M[C]

def identity[A]: A => M[A]

}
@kelleyrobinson
trait Monad[M[_]]
extends Functor[M]
/* with Monoid[ _ => M[_] ] */ {


def pure[A](a: A): M[A]

def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]



def map[A, B](a: M[A])(fn: A => B): M[B]

def append[A, B, C](f1: A => M[B], f2: B => M[C]): A => M[C]

def identity[A]: A => M[A]

}
@kelleyrobinson
trait Monad[M[_]]
extends Functor[M]
/* with Monoid[ _ => M[_] ] */ {


def pure[A](a: A): M[A]

def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]



def map[A, B](a: M[A])(fn: A => B): M[B]

def append[A, B, C](f1: A => M[B], f2: B => M[C]): A => M[C]

def identity[A]: A => M[A]

}
@kelleyrobinson
object FunctionComposition /* extends Monoid[_ => _] */{



...
}
trait Monad[M[_]] /* extends Monoid[_ => M[_]] */{


...
}
WHY THE FREE MONAD ISN’T FREE
- Monoids, Functors & Monads
- How to be “Free”
- Why & Why Not “Free”
- Alternatives
- Real World Applications
$
@kelleyrobinson
WHY THE FREE MONAD ISN'T FREE
The word "free" is
used in the sense of
"unrestricted" rather
than "zero-cost"
$
@kelleyrobinson
WHY THE FREE MONAD ISN'T FREE
"Freedom not beer"
https://en.wikipedia.org/wiki/Gratis_versus_libre#/media/File:Galuel_RMS_-_free_as_free_speech,_not_as_free_beer.png
WHY THE FREE MONAD ISN’T FREE
Free Monoids
@kelleyrobinson
@kelleyrobinson
trait Monoid[A] {


def append(a: A, b: A): A

def identity: A

}
WHY THE FREE MONAD ISN’T FREE
Free Monoids
• Free from interpretation
• No lost input data when
appending
@kelleyrobinson
image credit: http://celestemorris.com
@kelleyrobinson
// I'm free!
class ListConcat[A] extends Monoid[List[A]] {

def append(a: List[A], b: List[A]): List[A] =
a ++ b

def identity: List[A] = List.empty[A]

}
@kelleyrobinson
// I'm not free :(
object IntegerAddition extends Monoid[Int] {



def append(a: Int, b: Int): Int = a + b



def identity: Int = 0



}
WHY THE FREE MONAD ISN’T FREE
Free Monads
@kelleyrobinson
Don't lose any data!
(that means no evaluating functions)
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson
@kelleyrobinson
def notFreeAppend[A, B, C]
(f1: A => M[B], f2: B => M[C]): A => M[C] = {
a: A =>

// evaluate f1
val bs: M[B] = f1(a)
// evaluate f2

val cs: M[C] = flatMap(bs) { b: B => f2(b) }

cs
}
@kelleyrobinson
sealed trait Free[F[_], A] { self =>



}

@kelleyrobinson
sealed trait Free[F[_], A] { self =>

}



case class Return[F[_], A](given: A) extends Free[F, A]
@kelleyrobinson
sealed trait Free[F[_], A] { self =>



}



case class Return[F[_], A](given: A) extends Free[F, A]
case class Suspend[F[_], A](fn: F[A]) extends Free[F, A]

@kelleyrobinson
sealed trait Free[F[_], A] { self =>



}



case class Return[F[_], A](given: A) extends Free[F, A]
case class Suspend[F[_], A](fn: F[A]) extends Free[F, A]

case class FlatMap[F[_], A, B]
(free: Free[F, A], fn: A => Free[F, B])
extends Free[F, B]
@kelleyrobinson
sealed trait Free[F[_], A] { self =>
def flatMap ...
def pure ...
def map ...
}



case class Return[F[_], A](given: A) extends Free[F, A]
case class Suspend[F[_], A](fn: F[A]) extends Free[F, A]

case class FlatMap[F[_], A, B]
(free: Free[F, A], fn: A => Free[F, B])
extends Free[F, B]
@kelleyrobinson
sealed trait Todo[A]

case class NewTask[A](task: A) extends Todo[A]

case class CompleteTask[A](task: A) extends Todo[A]

case class GetTasks[A](default: A) extends Todo[A]
def newTask[A](task: A): Free[Todo, A] =
Suspend(NewTask(task))

def completeTask[A](task: A): Free[Todo, A] =
Suspend(CompleteTask(task))

def getTasks[A](default: A): Free[Todo, A] =
Suspend(GetTasks(default))
@kelleyrobinson
val todos: Free[Todo, Map[String, Boolean]] =

for {

_ <- newTask("Go to scala days")

_ <- newTask("Write a novel")

_ <- newTask("Meet Tina Fey")

_ <- completeTask("Go to scala days")

tsks <- getTasks(Map.empty)

} yield tsks
@kelleyrobinson
val todosExpanded: Free[Todo, Map[String, Boolean]] =

FlatMap(

Suspend(NewTask("Go to scala days")), (a: String) =>

FlatMap(

Suspend(NewTask("Write a novel")), (b: String) =>

FlatMap(

Suspend(NewTask("Meet Tina Fey")), (c: String) =>

FlatMap(

Suspend(CompleteTask("Go to scala days")),
(d: String) =>
Suspend(GetTasks(default = Map.empty))

)

)

)

)
WHY THE FREE MONAD ISN’T FREE
- Monoids, Functors & Monads
- How to be “Free”
- Why & Why Not “Free”
- Alternatives
- Real World Applications
$
@kelleyrobinson
WHY THE FREE MONAD ISN'T FREE
What's the point?
• Defer side effects
• Multiple interpreters
• Stack safety
@kelleyrobinson
@kelleyrobinson


(1 to 1000).flatMap { i =>

doSomething(i).flatMap { j =>

doSomethingElse(j).flatMap { k =>

doAnotherThing(k).map { l =>

...
WHY THE FREE MONAD ISN’T FREE
“Let’s just trampoline it and
add the Free Monad”
@kelleyrobinson
WHY THE FREE MONAD ISN’T FREE
Trampolining
Express it in a loop
@kelleyrobinson
WHY THE FREE MONAD ISN’T FREE
The Free Monad
uses heap instead of
using stack.
@kelleyrobinson
@kelleyrobinson
val todosExpanded: Free[Todo, Map[String, Boolean]] =

FlatMap(

Suspend(NewTask("Go to scala days")), (a: String) =>

FlatMap(

Suspend(NewTask("Write a novel")), (b: String) =>

FlatMap(

Suspend(NewTask("Meet Tina Fey")), (c: String) =>

FlatMap(

Suspend(CompleteTask("Go to scala days")),
(d: String) =>
Suspend(GetTasks(default = Map.empty))

)

)

)

)
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson
Evaluating
Use a loop
@kelleyrobinson
def runFree[F[_], G[_], A]
(f: Free[F, A])
(transform: FunctorTransformer[F, G])
(implicit G: Monad[G]): G[A]
@kelleyrobinson
def runFree[F[_], G[_], A]
(f: Free[F, A])
(transform: FunctorTransformer[F, G])
(implicit G: Monad[G]): G[A]
Turn F into G -
AKA "Natural Transformation"Input
`G` must be a monad so we can flatMap
@kelleyrobinson
// or 'NaturalTransformation'

trait FunctorTransformer[F[_], G[_]] {

def apply[A](f: F[A]): G[A]

}

// Common symbolic operator
type ~>[F[_], G[_]] = FunctorTransformer[F, G]
@kelleyrobinson
/* Function body */
@annotation.tailrec

def tailThis(free: Free[F, A]): Free[F, A] = free match {

case FlatMap(FlatMap(fr, fn1), fn2) => ...
case FlatMap(Return(a), fn) => ...
case _ => ...

}



tailThis(f) match {

case Return(a) => ...

case Suspend(fa) => ...
case FlatMap(Suspend(fa), fn) => ...
case _ => ...

}
https://github.com/robinske/monad-examples
@kelleyrobinson
tailThis(f) match {

case Return(a) => ...

case Suspend(fa) => transform(fa)
case FlatMap(Suspend(fa), fn) =>
monad.flatMap(transform(fa))(a =>
runFree(fn(a))(transform))
case _ => ...

}
https://github.com/robinske/monad-examples
@kelleyrobinson
def runLoop[F[_], G[_], A](...): G[A] = {

var eval: Free[F, A] = f



while (true) {

eval match {

case Return(a) => ...

case Suspend(fa) => ...

case FlatMap(Suspend(fa), fn) => ...

case FlatMap(FlatMap(given, fn1), fn2) => ...

case FlatMap(Return(s), fn) => ...

}

}



throw new AssertionError("Unreachable")

}
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson
Evaluating
Applies transformation on
`Suspend`
Trampolining for stack safety
@kelleyrobinson
// or 'NaturalTransformation'

trait FunctorTransformer[F[_], G[_]] {

def apply[A](f: F[A]): G[A]

}

// Common symbolic operator
type ~>[F[_], G[_]] = FunctorTransformer[F, G]
@kelleyrobinson
type Id[A] = A
case class TestEvaluator(var model: Map[String, Boolean])
extends FunctorTransformer[Todo, Id] {



def apply[A](a: Todo[A]): Id[A]
}
@kelleyrobinson
a match {
case NewTask(task) =>

model = model + (task.toString -> false)

task

case CompleteTask(task) =>

model = model + (task.toString -> true)

task

case GetTasks(default) =>

model.asInstanceOf[A]
}
@kelleyrobinson
it("should evaluate todos") {

val result =
runFree(todos)(TestEvaluator(Map.empty))

val expected: Map[String, Boolean] =

Map(

"Go to scala days" -> true,

"Write a novel" -> false,

"Meet Tina Fey" -> false

)

result shouldBe expected

}
@kelleyrobinson
case object ActionTestEvaluator
extends FunctorTransformer[Todo, Id] {


var actions: List[Todo[String]] = List.empty

def apply[A](a: Todo[A]): Id[A]
}
@kelleyrobinson
a match {
case NewTask(task) =>

actions = actions :+ NewTask(task.toString)

task

case CompleteTask(task) =>

actions = actions :+ CompleteTask(task.toString)

task

case GetTasks(default) =>

actions = actions :+ GetTasks("")

default
}
@kelleyrobinson
it("should evaluate todos actions in order") {

runFree(todos)(ActionTestEvaluator)



val expected: List[Todo[String]] =

List(

NewTask("Go to scala days"),

NewTask("Write a novel"),
NewTask("Meet Tina Fey"),

CompleteTask("Go to scala days"),
GetTasks("")

)


ActionTestEvaluator.actions shouldBe expected

}
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson
Defining multiple interpreters allows
you to test side-effecting code without
using testing mocks.
@kelleyrobinson
// Production Interpreter
def apply[A](a: Todo[A]): Option[A] = {

a match {

case NewTask(task) =>

/**
* Some if DB write succeeds
* None if DB write fails
*
*/

case CompleteTask(task) => ...

case GetTasks(default) => ...

}

}
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson
Justifications
• Defer side effects
• Multiple interpreters
• Stack safety
WHY THE FREE MONAD ISN'T FREE
#BlueSkyScala
The path to learning is broken
@kelleyrobinson
Credit: Jessica Kerr
WHY THE FREE MONAD ISN'T FREE
Freedom isn't free
Reasons to avoid the Free Monad
• Boilerplate
• Learning curve
• Alternatives
@kelleyrobinson
Credit: Jessica Kerr
WHY THE FREE MONAD ISN’T FREE
- Monoids, Functors & Monads
- How to be “Free”
- Why & Why Not “Free”
- Alternatives
- Real World Applications
$
@kelleyrobinson
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson
Know your domain
WHY THE FREE MONAD ISN'T FREE
Functional Spectrum
Where does your team fall?
Java Haskell
WHY THE FREE MONAD ISN'T FREE
Functional Spectrum
Where does your team fall?
Java Haskell
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson
Alternatives for
maintaining stack
safety
@kelleyrobinson
final override def map[B, That](f: A => B)
(implicit bf: CanBuildFrom[List[A], B, That]): That = {

if (bf eq List.ReusableCBF) {

if (this eq Nil) Nil.asInstanceOf[That] else {

val h = new ::[B](f(head), Nil)

var t: ::[B] = h

var rest = tail

while (rest ne Nil) {

val nx = new ::(f(rest.head), Nil)

t.tl = nx

t = nx

rest = rest.tail

}

h.asInstanceOf[That]

}

}

else super.map(f)

}
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson
Alternatives for
managing side
effects
@kelleyrobinson
import java.sql.ResultSet



case class Person(name: String, age: Int)



def getPerson(rs: ResultSet): Person = {

val name = rs.getString(1)

val age = rs.getInt(2)

Person(name, age)

}
@kelleyrobinson
def handleFailure[A](f: => A): ActionResult / A = {

Try(f) match {

case Success(res) => res.right

case Failure(e) =>
InternalServerError(reason = e.getMessage).left

}

}


handleFailure(getPerson(rs))
WHY THE FREE MONAD ISN’T FREE
- Monoids, Functors & Monads
- How to be “Free”
- Why & Why Not “Free”
- Alternatives
- Real World Applications
$
@kelleyrobinson
WHY THE FREE MONAD ISN'T FREE
Scalaz
Scalaz is a Scala library for functional programming.
http://scalaz.github.io/scalaz/
Cats
Lightweight, modular, and extensible library for
functional programming.
http://typelevel.org/cats/
@kelleyrobinson
http://www.slideshare.net/jamesskillsmatter/real-world-scalaz
WHY THE FREE MONAD ISN'T FREE
Examples
• Doobie
• scalaz.concurrent.Task
@kelleyrobinson
https://github.com/tpolecat/doobie
@kelleyrobinson
import scalaz.concurrent.Task
def apply(conf: Config, messages: List[SQSMessage]): Unit = {

val tasks = messages.map(m => Task {

processSQSMessage(conf, m)

})



Task.gatherUnordered(tasks).attemptRun match {

case -/(exp) => error(s"Unable to process message")

case _ => ()

}

}
@kelleyrobinson
// yikes
object Task {

implicit val taskInstance:
Nondeterminism[Task] with Catchable[Task]
with MonadError[({type λ[α,β] =
Task[β]})#λ,Throwable] = new
Nondeterminism[Task] with Catchable[Task]
with MonadError[({type λ[α,β] =
Task[β]})#λ,Throwable] { ... }
}
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson
My experience...
...what happened?
WHY THE FREE MONAD ISN’T FREE
- Know your domain
- Use clean abstractions
- Share knowledge
$
@kelleyrobinson
Thank You!
@kelleyrobinson
hello@krobinson.me
WHY THE FREE MONAD ISN’T FREE
@kelleyrobinson
Acknowledgements & Resources
Special thanks to:
• Sharethrough
• Rúnar Bjarnason
• Rob Norris
• Eugene Yokota
• Jessica Kerr
• David Hoyt
• Danielle Sucher
• Charles Ruhland
Resources for learning more about Free Monads:
• http://blog.higher-order.com/assets/trampolines.pdf
• http://eed3si9n.com/learning-scalaz/
• https://stackoverflow.com/questions/44965/what-is-a-monad
• https://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/
• http://hseeberger.github.io/blog/2010/11/25/introduction-to-category-theory-in-scala/
• https://en.wikipedia.org/wiki/Free_object
• https://softwaremill.com/free-monads/
• https://github.com/davidhoyt/kool-aid/
• https://www.youtube.com/watch?v=T4956GI-6Lw
Other links and resources:
• https://skillsmatter.com/skillscasts/6483-keynote-scaling-intelligence-moving-ideas-forward
• https://stackoverflow.com/questions/7213676/forall-in-scala but that boilerplate

More Related Content

What's hot

What's hot (20)

Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)
 
Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)
 
Functional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioFunctional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis Atencio
 
Capabilities for Resources and Effects
Capabilities for Resources and EffectsCapabilities for Resources and Effects
Capabilities for Resources and Effects
 
How to successfully manage a ZIO fiber’s lifecycle - Functional Scala 2021
How to successfully manage a ZIO fiber’s lifecycle - Functional Scala 2021How to successfully manage a ZIO fiber’s lifecycle - Functional Scala 2021
How to successfully manage a ZIO fiber’s lifecycle - Functional Scala 2021
 
Generics in java
Generics in javaGenerics in java
Generics in java
 
Domain Modeling in a Functional World
Domain Modeling in a Functional WorldDomain Modeling in a Functional World
Domain Modeling in a Functional World
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
Izumi 1.0: Your Next Scala Stack
Izumi 1.0: Your Next Scala StackIzumi 1.0: Your Next Scala Stack
Izumi 1.0: Your Next Scala Stack
 
OWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling PicklesOWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling Pickles
 
Be Smart, Constrain Your Types to Free Your Brain!
Be Smart, Constrain Your Types to Free Your Brain!Be Smart, Constrain Your Types to Free Your Brain!
Be Smart, Constrain Your Types to Free Your Brain!
 
Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)
 
Design Patterns in Modern C++
Design Patterns in Modern C++Design Patterns in Modern C++
Design Patterns in Modern C++
 
Java 8 lambda expressions
Java 8 lambda expressionsJava 8 lambda expressions
Java 8 lambda expressions
 
Being Functional on Reactive Streams with Spring Reactor
Being Functional on Reactive Streams with Spring ReactorBeing Functional on Reactive Streams with Spring Reactor
Being Functional on Reactive Streams with Spring Reactor
 
non-strict functions, bottom and scala by-name parameters
non-strict functions, bottom and scala by-name parametersnon-strict functions, bottom and scala by-name parameters
non-strict functions, bottom and scala by-name parameters
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022
 
Peeking inside the engine of ZIO SQL.pdf
Peeking inside the engine of ZIO SQL.pdfPeeking inside the engine of ZIO SQL.pdf
Peeking inside the engine of ZIO SQL.pdf
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
 

Similar to Why The Free Monad isn't Free

Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free Monads
John De Goes
 
Algebraic Data Types and Origami Patterns
Algebraic Data Types and Origami PatternsAlgebraic Data Types and Origami Patterns
Algebraic Data Types and Origami Patterns
Vasil Remeniuk
 
The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final Tagless
John De Goes
 

Similar to Why The Free Monad isn't Free (20)

Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
 
Monad and Algebraic Design in Functional Programming
Monad and Algebraic Design in Functional ProgrammingMonad and Algebraic Design in Functional Programming
Monad and Algebraic Design in Functional Programming
 
Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverse
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free Monads
 
Algebraic Data Types and Origami Patterns
Algebraic Data Types and Origami PatternsAlgebraic Data Types and Origami Patterns
Algebraic Data Types and Origami Patterns
 
Monads and friends demystified
Monads and friends demystifiedMonads and friends demystified
Monads and friends demystified
 
Kotlin Introduction with Android applications
Kotlin Introduction with Android applicationsKotlin Introduction with Android applications
Kotlin Introduction with Android applications
 
Running Free with the Monads
Running Free with the MonadsRunning Free with the Monads
Running Free with the Monads
 
The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final Tagless
 
Beyond Scala Lens
Beyond Scala LensBeyond Scala Lens
Beyond Scala Lens
 
Kleisli composition, flatMap, join, map, unit - implementation and interrelation
Kleisli composition, flatMap, join, map, unit - implementation and interrelationKleisli composition, flatMap, join, map, unit - implementation and interrelation
Kleisli composition, flatMap, join, map, unit - implementation and interrelation
 
All You Need is Fold
All You Need is FoldAll You Need is Fold
All You Need is Fold
 
Fp in scala with adts
Fp in scala with adtsFp in scala with adts
Fp in scala with adts
 
Scala best practices
Scala best practicesScala best practices
Scala best practices
 
Fp in scala part 1
Fp in scala part 1Fp in scala part 1
Fp in scala part 1
 
7 Habits For a More Functional Swift
7 Habits For a More Functional Swift7 Habits For a More Functional Swift
7 Habits For a More Functional Swift
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator Pattern
 
Optics with monocle - Modeling the part and the whole
Optics with monocle - Modeling the part and the wholeOptics with monocle - Modeling the part and the whole
Optics with monocle - Modeling the part and the whole
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritance
 
The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)
 

More from Kelley Robinson

More from Kelley Robinson (20)

Protecting your phone verification flow from fraud & abuse
Protecting your phone verification flow from fraud & abuseProtecting your phone verification flow from fraud & abuse
Protecting your phone verification flow from fraud & abuse
 
Preventing phone verification fraud (SMS pumping)
Preventing phone verification fraud (SMS pumping)Preventing phone verification fraud (SMS pumping)
Preventing phone verification fraud (SMS pumping)
 
Auth on the web: better authentication
Auth on the web: better authenticationAuth on the web: better authentication
Auth on the web: better authentication
 
WebAuthn
WebAuthnWebAuthn
WebAuthn
 
Introduction to Public Key Cryptography
Introduction to Public Key CryptographyIntroduction to Public Key Cryptography
Introduction to Public Key Cryptography
 
2FA in 2020 and Beyond
2FA in 2020 and Beyond2FA in 2020 and Beyond
2FA in 2020 and Beyond
 
Identiverse 2020 - Account Recovery with 2FA
Identiverse 2020 - Account Recovery with 2FAIdentiverse 2020 - Account Recovery with 2FA
Identiverse 2020 - Account Recovery with 2FA
 
Designing customer account recovery in a 2FA world
Designing customer account recovery in a 2FA worldDesigning customer account recovery in a 2FA world
Designing customer account recovery in a 2FA world
 
Introduction to SHAKEN/STIR
Introduction to SHAKEN/STIRIntroduction to SHAKEN/STIR
Introduction to SHAKEN/STIR
 
Intro to SHAKEN/STIR
Intro to SHAKEN/STIRIntro to SHAKEN/STIR
Intro to SHAKEN/STIR
 
PSD2, SCA, WTF?
PSD2, SCA, WTF?PSD2, SCA, WTF?
PSD2, SCA, WTF?
 
Building a Better Scala Community
Building a Better Scala CommunityBuilding a Better Scala Community
Building a Better Scala Community
 
BSides SF - Contact Center Authentication
BSides SF - Contact Center AuthenticationBSides SF - Contact Center Authentication
BSides SF - Contact Center Authentication
 
Communication @ Startups
Communication @ StartupsCommunication @ Startups
Communication @ Startups
 
Contact Center Authentication
Contact Center AuthenticationContact Center Authentication
Contact Center Authentication
 
Authentication Beyond SMS
Authentication Beyond SMSAuthentication Beyond SMS
Authentication Beyond SMS
 
BSides PDX - Threat Modeling Authentication
BSides PDX - Threat Modeling AuthenticationBSides PDX - Threat Modeling Authentication
BSides PDX - Threat Modeling Authentication
 
SIGNAL - Practical Cryptography
SIGNAL - Practical CryptographySIGNAL - Practical Cryptography
SIGNAL - Practical Cryptography
 
2FA Best Practices
2FA Best Practices2FA Best Practices
2FA Best Practices
 
Practical Cryptography
Practical CryptographyPractical Cryptography
Practical Cryptography
 

Recently uploaded

Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak HamilCara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Kandungan 087776558899
 
Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar ≼🔝 Delhi door step de...
Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar  ≼🔝 Delhi door step de...Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar  ≼🔝 Delhi door step de...
Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar ≼🔝 Delhi door step de...
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
VIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 Booking
dharasingh5698
 

Recently uploaded (20)

Thermal Engineering Unit - I & II . ppt
Thermal Engineering  Unit - I & II . pptThermal Engineering  Unit - I & II . ppt
Thermal Engineering Unit - I & II . ppt
 
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance BookingCall Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
 
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak HamilCara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
 
Bhosari ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready For ...
Bhosari ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready For ...Bhosari ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready For ...
Bhosari ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready For ...
 
Call Girls Pimpri Chinchwad Call Me 7737669865 Budget Friendly No Advance Boo...
Call Girls Pimpri Chinchwad Call Me 7737669865 Budget Friendly No Advance Boo...Call Girls Pimpri Chinchwad Call Me 7737669865 Budget Friendly No Advance Boo...
Call Girls Pimpri Chinchwad Call Me 7737669865 Budget Friendly No Advance Boo...
 
data_management_and _data_science_cheat_sheet.pdf
data_management_and _data_science_cheat_sheet.pdfdata_management_and _data_science_cheat_sheet.pdf
data_management_and _data_science_cheat_sheet.pdf
 
UNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its PerformanceUNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its Performance
 
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
 
Double rodded leveling 1 pdf activity 01
Double rodded leveling 1 pdf activity 01Double rodded leveling 1 pdf activity 01
Double rodded leveling 1 pdf activity 01
 
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
 
Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar ≼🔝 Delhi door step de...
Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar  ≼🔝 Delhi door step de...Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar  ≼🔝 Delhi door step de...
Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar ≼🔝 Delhi door step de...
 
Booking open Available Pune Call Girls Koregaon Park 6297143586 Call Hot Ind...
Booking open Available Pune Call Girls Koregaon Park  6297143586 Call Hot Ind...Booking open Available Pune Call Girls Koregaon Park  6297143586 Call Hot Ind...
Booking open Available Pune Call Girls Koregaon Park 6297143586 Call Hot Ind...
 
Thermal Engineering -unit - III & IV.ppt
Thermal Engineering -unit - III & IV.pptThermal Engineering -unit - III & IV.ppt
Thermal Engineering -unit - III & IV.ppt
 
VIP Model Call Girls Kothrud ( Pune ) Call ON 8005736733 Starting From 5K to ...
VIP Model Call Girls Kothrud ( Pune ) Call ON 8005736733 Starting From 5K to ...VIP Model Call Girls Kothrud ( Pune ) Call ON 8005736733 Starting From 5K to ...
VIP Model Call Girls Kothrud ( Pune ) Call ON 8005736733 Starting From 5K to ...
 
Thermal Engineering-R & A / C - unit - V
Thermal Engineering-R & A / C - unit - VThermal Engineering-R & A / C - unit - V
Thermal Engineering-R & A / C - unit - V
 
VIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 Booking
 
CCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete Record
CCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete RecordCCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete Record
CCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete Record
 
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced LoadsFEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
 
Double Revolving field theory-how the rotor develops torque
Double Revolving field theory-how the rotor develops torqueDouble Revolving field theory-how the rotor develops torque
Double Revolving field theory-how the rotor develops torque
 
Booking open Available Pune Call Girls Pargaon 6297143586 Call Hot Indian Gi...
Booking open Available Pune Call Girls Pargaon  6297143586 Call Hot Indian Gi...Booking open Available Pune Call Girls Pargaon  6297143586 Call Hot Indian Gi...
Booking open Available Pune Call Girls Pargaon 6297143586 Call Hot Indian Gi...
 

Why The Free Monad isn't Free

  • 1.
  • 2. [error] Exception encountered [error] java.lang.StackOverflowError
  • 3. WHY THE FREE MONAD ISN’T FREE “Let’s just trampoline it and add the Free Monad” @kelleyrobinson
  • 4. WHY THE FREE MONAD ISN’T FREE @kelleyrobinson “Let’s just trampoline it and add the Free Monad”
  • 5.
  • 6. Why The Free Monad Isn’t Free Kelley Robinson Data & Infrastructure Engineer Sharethrough @kelleyrobinson
  • 7. WHY THE FREE MONAD ISN’T FREE - Monoids, Functors & Monads - How to be “Free” - Why & Why Not “Free” - Alternatives - Real World Applications $ @kelleyrobinson
  • 8. WHY THE FREE MONAD ISN’T FREE github.com/robinske/monad-examples
  • 9. WHY THE FREE MONAD ISN’T FREE https://twitter.com/rickasaurus/status/705134684427128833
  • 10. WHY THE FREE MONAD ISN’T FREE Monoids @kelleyrobinson
  • 11. @kelleyrobinson trait Monoid[A] { 
 def append(a: A, b: A): A 
 def identity: A
 }
  • 12. WHY THE FREE MONAD ISN'T FREE Monoids Image credit: deluxebattery.com
  • 13. WHY THE FREE MONAD ISN'T FREE Properties Identity: "no-op" value Associativity: grouping doesn't matter @kelleyrobinson
  • 14. @kelleyrobinson object StringConcat extends Monoid[String] {
 
 def append(a: String, b: String): String = a + b
 
 def identity: String = ""
 
 }
  • 15. @kelleyrobinson object IntegerAddition extends Monoid[Int] {
 
 def append(a: Int, b: Int): Int = a + b
 
 def identity: Int = 0
 
 }
  • 16. @kelleyrobinson object IntegerMultiplication extends Monoid[Int] {
 
 def append(a: Int, b: Int): Int = a * b
 
 def identity: Int = 1
 
 }
  • 17. @kelleyrobinson object FunctionComposition /* extends Monoid[_=>_] */ {
 
 def append[A, B, C](f1: A => B, f2: B => C): A => C = (a: A) => f2(f1(a))
 
 def identity[A]: A => A = (a: A) => a 
 }
  • 18. @kelleyrobinson object FunctionComposition /* extends Monoid[_=>_] */ {
 
 def append[A, B, C](f1: A => B, f2: B => C): A => C = (a: A) => f2(f1(a))
 
 def identity[A]: A => A = (a: A) => a 
 }
  • 19. WHY THE FREE MONAD ISN’T FREE Functors @kelleyrobinson
  • 20. @kelleyrobinson trait Functor[F[_]] {
 
 def map[A, B](a: F[A])(fn: A => B): F[B]
 
 }
  • 21. WHY THE FREE MONAD ISN'T FREE @kelleyrobinson Properties Identity: "no-op" value Composition: grouping doesn't matter
  • 22. @kelleyrobinson sealed trait Option[+A]
 case class Some[A](a: A) extends Option[A]
 case object None extends Option[Nothing] object OptionFunctor extends Functor[Option] {
 
 def map[A, B](a: Option[A])(fn: A => B): Option[B] =
 a match {
 case Some(something) => Some(fn(something))
 case None => None
 }
 }
  • 23. @kelleyrobinson it("should follow the identity law") {
 def identity[A](a: A): A = a
 assert(map(Some("foo"))(identity) == Some("foo"))
 }
  • 24. @kelleyrobinson it("should follow the composition law") { val f: String => String = s => s + "a"
 val g: String => String = s => s + "l" val h: String => String = s => s + "a" assert( map(Some("sc"))(f andThen g andThen h) == map(map(map(Some("sc"))(f))(g))(h) == "scala" ) }
  • 25. Functors are Endofunctors** **in Scala WHY THE FREE MONAD ISN’T FREE @kelleyrobinson
  • 26. WHY THE FREE MONAD ISN’T FREE Monads @kelleyrobinson
  • 27. "The term monad is a bit vacuous if you are not a mathematician. An alternative term is computation builder." WHY THE FREE MONAD ISN’T FREE @kelleyrobinson http://stackoverflow.com/questions/44965/what-is-a-monad
  • 28. @kelleyrobinson trait Monad[M[_]] { 
 def pure[A](a: A): M[A]
 def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]
 }
  • 29. @kelleyrobinson sealed trait Option[+A]
 case class Some[A](a: A) extends Option[A]
 case object None extends Option[Nothing]
 
 object OptionMonad extends Monad[Option] {
 
 def pure[A](a: A): Option[A] = Some(a)
 
 def flatMap[A, B](a: Option[A])(fn: A => Option[B]): Option[B] =
 a match {
 case Some(something) => fn(something)
 case None => None
 }
 }
  • 30. @kelleyrobinson trait Monad[M[_]] { 
 def pure[A](a: A): M[A]
 def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]
 }
  • 31. @kelleyrobinson trait Monad[M[_]] {
 def pure[A](a: A): M[A]
 def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]
 
 def map[A, B](a: M[A])(fn: A => B): M[B] = {
 flatMap(a){ b: A => pure(fn(b)) }
 } 
 }
  • 32. @kelleyrobinson trait Monad[M[_]] { def pure[A](a: A): M[A]
 def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]
 
 def map[A, B](a: M[A])(fn: A => B): M[B] = {
 flatMap(a){ b: A => pure(fn(b)) }
 }
 }
  • 33. @kelleyrobinson trait Monad[M[_]] {
 def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]
 def append[A, B, C] (f1: A => M[B], f2: B => M[C]): A => M[C] = { a: A =>
 val bs: M[B] = f1(a)
 val cs: M[C] = flatMap(bs) { b: B => f2(b) }
 cs
 } 
 }
  • 34. @kelleyrobinson trait Monad[M[_]] {
 def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]
 def append[A, B, C] (f1: A => M[B], f2: B => M[C]): A => M[C] = { a: A =>
 val bs: M[B] = f1(a)
 val cs: M[C] = flatMap(bs) { b: B => f2(b) }
 cs
 } 
 }
  • 35. WHY THE FREE MONAD ISN'T FREE Properties Identity: "no-op" value Composition: grouping doesn't matter @kelleyrobinson
  • 36. WHY THE FREE MONAD ISN'T FREE Compose functions for values in a context Think: Lists, Options, Futures @kelleyrobinson
  • 37. trait Monad[M[_]] extends Functor[M] /* with Monoid[_=>M[_]] */ { 
 def pure[A](a: A): M[A]
 def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]
 
 def map[A, B](a: M[A])(fn: A => B): M[B]
 def append[A, B, C](f1: A => M[B], f2: B => M[C]): A => M[C]
 def identity[A]: A => M[A]
 } @kelleyrobinson trait Monad[M[_]] extends Functor[M] /* with Monoid[ _ => M[_] ] */ { 
 def pure[A](a: A): M[A]
 def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]
 
 def map[A, B](a: M[A])(fn: A => B): M[B]
 def append[A, B, C](f1: A => M[B], f2: B => M[C]): A => M[C]
 def identity[A]: A => M[A]
 }
  • 38. @kelleyrobinson trait Monad[M[_]] extends Functor[M] /* with Monoid[ _ => M[_] ] */ { 
 def pure[A](a: A): M[A]
 def flatMap[A, B](a: M[A])(fn: A => M[B]): M[B]
 
 def map[A, B](a: M[A])(fn: A => B): M[B]
 def append[A, B, C](f1: A => M[B], f2: B => M[C]): A => M[C]
 def identity[A]: A => M[A]
 }
  • 39. @kelleyrobinson object FunctionComposition /* extends Monoid[_ => _] */{
 
 ... } trait Monad[M[_]] /* extends Monoid[_ => M[_]] */{ 
 ... }
  • 40. WHY THE FREE MONAD ISN’T FREE - Monoids, Functors & Monads - How to be “Free” - Why & Why Not “Free” - Alternatives - Real World Applications $ @kelleyrobinson
  • 41. WHY THE FREE MONAD ISN'T FREE The word "free" is used in the sense of "unrestricted" rather than "zero-cost" $ @kelleyrobinson
  • 42. WHY THE FREE MONAD ISN'T FREE "Freedom not beer" https://en.wikipedia.org/wiki/Gratis_versus_libre#/media/File:Galuel_RMS_-_free_as_free_speech,_not_as_free_beer.png
  • 43. WHY THE FREE MONAD ISN’T FREE Free Monoids @kelleyrobinson
  • 44. @kelleyrobinson trait Monoid[A] { 
 def append(a: A, b: A): A
 def identity: A
 }
  • 45. WHY THE FREE MONAD ISN’T FREE Free Monoids • Free from interpretation • No lost input data when appending @kelleyrobinson image credit: http://celestemorris.com
  • 46. @kelleyrobinson // I'm free! class ListConcat[A] extends Monoid[List[A]] {
 def append(a: List[A], b: List[A]): List[A] = a ++ b
 def identity: List[A] = List.empty[A]
 }
  • 47. @kelleyrobinson // I'm not free :( object IntegerAddition extends Monoid[Int] {
 
 def append(a: Int, b: Int): Int = a + b
 
 def identity: Int = 0
 
 }
  • 48. WHY THE FREE MONAD ISN’T FREE Free Monads @kelleyrobinson
  • 49. Don't lose any data! (that means no evaluating functions) WHY THE FREE MONAD ISN’T FREE @kelleyrobinson
  • 50. @kelleyrobinson def notFreeAppend[A, B, C] (f1: A => M[B], f2: B => M[C]): A => M[C] = { a: A =>
 // evaluate f1 val bs: M[B] = f1(a) // evaluate f2
 val cs: M[C] = flatMap(bs) { b: B => f2(b) }
 cs }
  • 51. @kelleyrobinson sealed trait Free[F[_], A] { self =>
 
 }

  • 52. @kelleyrobinson sealed trait Free[F[_], A] { self =>
 }
 
 case class Return[F[_], A](given: A) extends Free[F, A]
  • 53. @kelleyrobinson sealed trait Free[F[_], A] { self =>
 
 }
 
 case class Return[F[_], A](given: A) extends Free[F, A] case class Suspend[F[_], A](fn: F[A]) extends Free[F, A]

  • 54. @kelleyrobinson sealed trait Free[F[_], A] { self =>
 
 }
 
 case class Return[F[_], A](given: A) extends Free[F, A] case class Suspend[F[_], A](fn: F[A]) extends Free[F, A]
 case class FlatMap[F[_], A, B] (free: Free[F, A], fn: A => Free[F, B]) extends Free[F, B]
  • 55. @kelleyrobinson sealed trait Free[F[_], A] { self => def flatMap ... def pure ... def map ... }
 
 case class Return[F[_], A](given: A) extends Free[F, A] case class Suspend[F[_], A](fn: F[A]) extends Free[F, A]
 case class FlatMap[F[_], A, B] (free: Free[F, A], fn: A => Free[F, B]) extends Free[F, B]
  • 56. @kelleyrobinson sealed trait Todo[A]
 case class NewTask[A](task: A) extends Todo[A]
 case class CompleteTask[A](task: A) extends Todo[A]
 case class GetTasks[A](default: A) extends Todo[A] def newTask[A](task: A): Free[Todo, A] = Suspend(NewTask(task))
 def completeTask[A](task: A): Free[Todo, A] = Suspend(CompleteTask(task))
 def getTasks[A](default: A): Free[Todo, A] = Suspend(GetTasks(default))
  • 57. @kelleyrobinson val todos: Free[Todo, Map[String, Boolean]] =
 for {
 _ <- newTask("Go to scala days")
 _ <- newTask("Write a novel")
 _ <- newTask("Meet Tina Fey")
 _ <- completeTask("Go to scala days")
 tsks <- getTasks(Map.empty)
 } yield tsks
  • 58. @kelleyrobinson val todosExpanded: Free[Todo, Map[String, Boolean]] =
 FlatMap(
 Suspend(NewTask("Go to scala days")), (a: String) =>
 FlatMap(
 Suspend(NewTask("Write a novel")), (b: String) =>
 FlatMap(
 Suspend(NewTask("Meet Tina Fey")), (c: String) =>
 FlatMap(
 Suspend(CompleteTask("Go to scala days")), (d: String) => Suspend(GetTasks(default = Map.empty))
 )
 )
 )
 )
  • 59. WHY THE FREE MONAD ISN’T FREE - Monoids, Functors & Monads - How to be “Free” - Why & Why Not “Free” - Alternatives - Real World Applications $ @kelleyrobinson
  • 60. WHY THE FREE MONAD ISN'T FREE What's the point? • Defer side effects • Multiple interpreters • Stack safety @kelleyrobinson
  • 61. @kelleyrobinson 
 (1 to 1000).flatMap { i =>
 doSomething(i).flatMap { j =>
 doSomethingElse(j).flatMap { k =>
 doAnotherThing(k).map { l =>
 ...
  • 62. WHY THE FREE MONAD ISN’T FREE “Let’s just trampoline it and add the Free Monad” @kelleyrobinson
  • 63. WHY THE FREE MONAD ISN’T FREE Trampolining Express it in a loop @kelleyrobinson
  • 64. WHY THE FREE MONAD ISN’T FREE The Free Monad uses heap instead of using stack. @kelleyrobinson
  • 65. @kelleyrobinson val todosExpanded: Free[Todo, Map[String, Boolean]] =
 FlatMap(
 Suspend(NewTask("Go to scala days")), (a: String) =>
 FlatMap(
 Suspend(NewTask("Write a novel")), (b: String) =>
 FlatMap(
 Suspend(NewTask("Meet Tina Fey")), (c: String) =>
 FlatMap(
 Suspend(CompleteTask("Go to scala days")), (d: String) => Suspend(GetTasks(default = Map.empty))
 )
 )
 )
 )
  • 66. WHY THE FREE MONAD ISN’T FREE @kelleyrobinson Evaluating Use a loop
  • 67. @kelleyrobinson def runFree[F[_], G[_], A] (f: Free[F, A]) (transform: FunctorTransformer[F, G]) (implicit G: Monad[G]): G[A]
  • 68. @kelleyrobinson def runFree[F[_], G[_], A] (f: Free[F, A]) (transform: FunctorTransformer[F, G]) (implicit G: Monad[G]): G[A] Turn F into G - AKA "Natural Transformation"Input `G` must be a monad so we can flatMap
  • 69. @kelleyrobinson // or 'NaturalTransformation'
 trait FunctorTransformer[F[_], G[_]] {
 def apply[A](f: F[A]): G[A]
 }
 // Common symbolic operator type ~>[F[_], G[_]] = FunctorTransformer[F, G]
  • 70. @kelleyrobinson /* Function body */ @annotation.tailrec
 def tailThis(free: Free[F, A]): Free[F, A] = free match {
 case FlatMap(FlatMap(fr, fn1), fn2) => ... case FlatMap(Return(a), fn) => ... case _ => ...
 }
 
 tailThis(f) match {
 case Return(a) => ...
 case Suspend(fa) => ... case FlatMap(Suspend(fa), fn) => ... case _ => ...
 } https://github.com/robinske/monad-examples
  • 71. @kelleyrobinson tailThis(f) match {
 case Return(a) => ...
 case Suspend(fa) => transform(fa) case FlatMap(Suspend(fa), fn) => monad.flatMap(transform(fa))(a => runFree(fn(a))(transform)) case _ => ...
 } https://github.com/robinske/monad-examples
  • 72. @kelleyrobinson def runLoop[F[_], G[_], A](...): G[A] = {
 var eval: Free[F, A] = f
 
 while (true) {
 eval match {
 case Return(a) => ...
 case Suspend(fa) => ...
 case FlatMap(Suspend(fa), fn) => ...
 case FlatMap(FlatMap(given, fn1), fn2) => ...
 case FlatMap(Return(s), fn) => ...
 }
 }
 
 throw new AssertionError("Unreachable")
 }
  • 73. WHY THE FREE MONAD ISN’T FREE @kelleyrobinson Evaluating Applies transformation on `Suspend` Trampolining for stack safety
  • 74. @kelleyrobinson // or 'NaturalTransformation'
 trait FunctorTransformer[F[_], G[_]] {
 def apply[A](f: F[A]): G[A]
 }
 // Common symbolic operator type ~>[F[_], G[_]] = FunctorTransformer[F, G]
  • 75. @kelleyrobinson type Id[A] = A case class TestEvaluator(var model: Map[String, Boolean]) extends FunctorTransformer[Todo, Id] {
 
 def apply[A](a: Todo[A]): Id[A] }
  • 76. @kelleyrobinson a match { case NewTask(task) =>
 model = model + (task.toString -> false)
 task
 case CompleteTask(task) =>
 model = model + (task.toString -> true)
 task
 case GetTasks(default) =>
 model.asInstanceOf[A] }
  • 77. @kelleyrobinson it("should evaluate todos") {
 val result = runFree(todos)(TestEvaluator(Map.empty))
 val expected: Map[String, Boolean] =
 Map(
 "Go to scala days" -> true,
 "Write a novel" -> false,
 "Meet Tina Fey" -> false
 )
 result shouldBe expected
 }
  • 78. @kelleyrobinson case object ActionTestEvaluator extends FunctorTransformer[Todo, Id] { 
 var actions: List[Todo[String]] = List.empty
 def apply[A](a: Todo[A]): Id[A] }
  • 79. @kelleyrobinson a match { case NewTask(task) =>
 actions = actions :+ NewTask(task.toString)
 task
 case CompleteTask(task) =>
 actions = actions :+ CompleteTask(task.toString)
 task
 case GetTasks(default) =>
 actions = actions :+ GetTasks("")
 default }
  • 80. @kelleyrobinson it("should evaluate todos actions in order") {
 runFree(todos)(ActionTestEvaluator)
 
 val expected: List[Todo[String]] =
 List(
 NewTask("Go to scala days"),
 NewTask("Write a novel"), NewTask("Meet Tina Fey"),
 CompleteTask("Go to scala days"), GetTasks("")
 ) 
 ActionTestEvaluator.actions shouldBe expected
 }
  • 81. WHY THE FREE MONAD ISN’T FREE @kelleyrobinson Defining multiple interpreters allows you to test side-effecting code without using testing mocks.
  • 82. @kelleyrobinson // Production Interpreter def apply[A](a: Todo[A]): Option[A] = {
 a match {
 case NewTask(task) =>
 /** * Some if DB write succeeds * None if DB write fails * */
 case CompleteTask(task) => ...
 case GetTasks(default) => ...
 }
 }
  • 83. WHY THE FREE MONAD ISN’T FREE @kelleyrobinson Justifications • Defer side effects • Multiple interpreters • Stack safety
  • 84. WHY THE FREE MONAD ISN'T FREE #BlueSkyScala The path to learning is broken @kelleyrobinson Credit: Jessica Kerr
  • 85. WHY THE FREE MONAD ISN'T FREE Freedom isn't free Reasons to avoid the Free Monad • Boilerplate • Learning curve • Alternatives @kelleyrobinson Credit: Jessica Kerr
  • 86. WHY THE FREE MONAD ISN’T FREE - Monoids, Functors & Monads - How to be “Free” - Why & Why Not “Free” - Alternatives - Real World Applications $ @kelleyrobinson
  • 87. WHY THE FREE MONAD ISN’T FREE @kelleyrobinson Know your domain
  • 88. WHY THE FREE MONAD ISN'T FREE Functional Spectrum Where does your team fall? Java Haskell
  • 89. WHY THE FREE MONAD ISN'T FREE Functional Spectrum Where does your team fall? Java Haskell
  • 90. WHY THE FREE MONAD ISN’T FREE @kelleyrobinson Alternatives for maintaining stack safety
  • 91. @kelleyrobinson final override def map[B, That](f: A => B) (implicit bf: CanBuildFrom[List[A], B, That]): That = {
 if (bf eq List.ReusableCBF) {
 if (this eq Nil) Nil.asInstanceOf[That] else {
 val h = new ::[B](f(head), Nil)
 var t: ::[B] = h
 var rest = tail
 while (rest ne Nil) {
 val nx = new ::(f(rest.head), Nil)
 t.tl = nx
 t = nx
 rest = rest.tail
 }
 h.asInstanceOf[That]
 }
 }
 else super.map(f)
 }
  • 92. WHY THE FREE MONAD ISN’T FREE @kelleyrobinson Alternatives for managing side effects
  • 93. @kelleyrobinson import java.sql.ResultSet
 
 case class Person(name: String, age: Int)
 
 def getPerson(rs: ResultSet): Person = {
 val name = rs.getString(1)
 val age = rs.getInt(2)
 Person(name, age)
 }
  • 94. @kelleyrobinson def handleFailure[A](f: => A): ActionResult / A = {
 Try(f) match {
 case Success(res) => res.right
 case Failure(e) => InternalServerError(reason = e.getMessage).left
 }
 } 
 handleFailure(getPerson(rs))
  • 95. WHY THE FREE MONAD ISN’T FREE - Monoids, Functors & Monads - How to be “Free” - Why & Why Not “Free” - Alternatives - Real World Applications $ @kelleyrobinson
  • 96. WHY THE FREE MONAD ISN'T FREE Scalaz Scalaz is a Scala library for functional programming. http://scalaz.github.io/scalaz/ Cats Lightweight, modular, and extensible library for functional programming. http://typelevel.org/cats/ @kelleyrobinson http://www.slideshare.net/jamesskillsmatter/real-world-scalaz
  • 97. WHY THE FREE MONAD ISN'T FREE Examples • Doobie • scalaz.concurrent.Task @kelleyrobinson https://github.com/tpolecat/doobie
  • 98. @kelleyrobinson import scalaz.concurrent.Task def apply(conf: Config, messages: List[SQSMessage]): Unit = {
 val tasks = messages.map(m => Task {
 processSQSMessage(conf, m)
 })
 
 Task.gatherUnordered(tasks).attemptRun match {
 case -/(exp) => error(s"Unable to process message")
 case _ => ()
 }
 }
  • 99. @kelleyrobinson // yikes object Task {
 implicit val taskInstance: Nondeterminism[Task] with Catchable[Task] with MonadError[({type λ[α,β] = Task[β]})#λ,Throwable] = new Nondeterminism[Task] with Catchable[Task] with MonadError[({type λ[α,β] = Task[β]})#λ,Throwable] { ... } }
  • 100. WHY THE FREE MONAD ISN’T FREE @kelleyrobinson My experience... ...what happened?
  • 101. WHY THE FREE MONAD ISN’T FREE - Know your domain - Use clean abstractions - Share knowledge $ @kelleyrobinson
  • 103. WHY THE FREE MONAD ISN’T FREE @kelleyrobinson Acknowledgements & Resources Special thanks to: • Sharethrough • Rúnar Bjarnason • Rob Norris • Eugene Yokota • Jessica Kerr • David Hoyt • Danielle Sucher • Charles Ruhland Resources for learning more about Free Monads: • http://blog.higher-order.com/assets/trampolines.pdf • http://eed3si9n.com/learning-scalaz/ • https://stackoverflow.com/questions/44965/what-is-a-monad • https://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/ • http://hseeberger.github.io/blog/2010/11/25/introduction-to-category-theory-in-scala/ • https://en.wikipedia.org/wiki/Free_object • https://softwaremill.com/free-monads/ • https://github.com/davidhoyt/kool-aid/ • https://www.youtube.com/watch?v=T4956GI-6Lw Other links and resources: • https://skillsmatter.com/skillscasts/6483-keynote-scaling-intelligence-moving-ideas-forward • https://stackoverflow.com/questions/7213676/forall-in-scala but that boilerplate