why the free monad isn't free

103

Upload: kelley-robinson

Post on 21-Apr-2017

9.640 views

Category:

Engineering


1 download

TRANSCRIPT

Page 1: Why The Free Monad isn't Free
Page 2: Why The Free Monad isn't Free

[error] Exception encountered [error] java.lang.StackOverflowError

Page 3: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

“Let’s just trampoline it and add the Free Monad”

@kelleyrobinson

Page 4: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

@kelleyrobinson

“Let’s just trampoline it and add the Free Monad”

Page 5: Why The Free Monad isn't Free
Page 6: Why The Free Monad isn't Free

Why The Free Monad Isn’t Free

Kelley Robinson Data & Infrastructure Engineer

Sharethrough

@kelleyrobinson

Page 7: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

- Monoids, Functors & Monads

- How to be “Free”

- Why & Why Not “Free”

- Alternatives

- Real World Applications

$

@kelleyrobinson

Page 8: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

github.com/robinske/monad-examples

Page 9: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

https://twitter.com/rickasaurus/status/705134684427128833

Page 10: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

Monoids

@kelleyrobinson

Page 11: Why The Free Monad isn't Free

@kelleyrobinson

trait Monoid[A] { def append(a: A, b: A): A def identity: A

}

Page 12: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN'T FREE

Monoids

Image credit: deluxebattery.com

Page 13: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN'T FREE

Properties

Identity: "no-op" value

Associativity: grouping doesn't matter

@kelleyrobinson

Page 14: Why The Free Monad isn't Free

@kelleyrobinson

object StringConcat extends Monoid[String] { def append(a: String, b: String): String = a + b def identity: String = "" }

Page 15: Why The Free Monad isn't Free

@kelleyrobinson

object IntegerAddition extends Monoid[Int] { def append(a: Int, b: Int): Int = a + b def identity: Int = 0 }

Page 16: Why The Free Monad isn't Free

@kelleyrobinson

object IntegerMultiplication extends Monoid[Int] { def append(a: Int, b: Int): Int = a * b def identity: Int = 1 }

Page 17: Why The Free Monad isn't Free

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

Page 18: Why The Free Monad isn't Free

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

Page 19: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

Functors

@kelleyrobinson

Page 20: Why The Free Monad isn't Free

@kelleyrobinson

trait Functor[F[_]] { def map[A, B](a: F[A])(fn: A => B): F[B] }

Page 21: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN'T FREE

@kelleyrobinson

Properties

Identity: "no-op" value

Composition: grouping doesn't matter

Page 22: Why The Free Monad isn't Free

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

Page 23: Why The Free Monad isn't Free

@kelleyrobinson

it("should follow the identity law") {

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

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

}

Page 24: Why The Free Monad isn't Free

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

Page 25: Why The Free Monad isn't Free

Functors are Endofunctors** **in Scala

WHY THE FREE MONAD ISN’T FREE

@kelleyrobinson

Page 26: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

Monads

@kelleyrobinson

Page 27: Why The Free Monad isn't Free

"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

Page 28: Why The Free Monad isn't Free

@kelleyrobinson

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

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

}

Page 29: Why The Free Monad isn't Free

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

Page 30: Why The Free Monad isn't Free

@kelleyrobinson

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

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

}

Page 31: Why The Free Monad isn't Free

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

Page 32: Why The Free Monad isn't Free

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

}

Page 33: Why The Free Monad isn't Free

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

Page 34: Why The Free Monad isn't Free

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

Page 35: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN'T FREE

Properties

Identity: "no-op" value

Composition: grouping doesn't matter

@kelleyrobinson

Page 36: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN'T FREE

Compose functions for values in a context

Think: Lists, Options, Futures

@kelleyrobinson

Page 37: Why The Free Monad isn't Free

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]

}

Page 38: Why The Free Monad isn't Free

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

}

Page 39: Why The Free Monad isn't Free

@kelleyrobinson

object FunctionComposition /* extends Monoid[_ => _] */{ ...

}

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

}

Page 40: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

- Monoids, Functors & Monads

- How to be “Free”

- Why & Why Not “Free”

- Alternatives

- Real World Applications

$

@kelleyrobinson

Page 41: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN'T FREE

The word "free" is used in the sense of "unrestricted" rather than "zero-cost"

$

@kelleyrobinson

Page 42: Why The Free Monad isn't Free

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

Page 43: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

Free Monoids

@kelleyrobinson

Page 44: Why The Free Monad isn't Free

@kelleyrobinson

trait Monoid[A] { def append(a: A, b: A): A

def identity: A

}

Page 45: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

Free Monoids • Free from interpretation

• No lost input data when

appending

@kelleyrobinson

image credit: http://celestemorris.com

Page 46: Why The Free Monad isn't Free

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

}

Page 47: Why The Free Monad isn't Free

@kelleyrobinson

// I'm not free :(

object IntegerAddition extends Monoid[Int] { def append(a: Int, b: Int): Int = a + b def identity: Int = 0 }

Page 48: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

Free Monads

@kelleyrobinson

Page 49: Why The Free Monad isn't Free

Don't lose any data! (that means no evaluating functions)

WHY THE FREE MONAD ISN’T FREE

@kelleyrobinson

Page 50: Why The Free Monad isn't Free

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

Page 51: Why The Free Monad isn't Free

@kelleyrobinson

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

}

Page 52: Why The Free Monad isn't Free

@kelleyrobinson

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

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

Page 53: Why The Free Monad isn't Free

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

Page 54: Why The Free Monad isn't Free

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

Page 55: Why The Free Monad isn't Free

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

Page 56: Why The Free Monad isn't Free

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

Page 57: Why The Free Monad isn't Free

@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

Page 58: Why The Free Monad isn't Free

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

Page 59: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

- Monoids, Functors & Monads

- How to be “Free”

- Why & Why Not “Free”

- Alternatives

- Real World Applications

$

@kelleyrobinson

Page 60: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN'T FREE

What's the point?

• Defer side effects

• Multiple interpreters

• Stack safety

@kelleyrobinson

Page 61: Why The Free Monad isn't Free

@kelleyrobinson

(1 to 1000).flatMap { i => doSomething(i).flatMap { j => doSomethingElse(j).flatMap { k => doAnotherThing(k).map { l => ...

Page 62: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

“Let’s just trampoline it and add the Free Monad”

@kelleyrobinson

Page 63: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

Trampolining Express it in a loop

@kelleyrobinson

Page 64: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

The Free Monad uses heap instead of using stack.

@kelleyrobinson

Page 65: Why The Free Monad isn't Free

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

Page 66: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

@kelleyrobinson

Evaluating Use a loop

Page 67: Why The Free Monad isn't Free

@kelleyrobinson

def runFree[F[_], G[_], A]

(f: Free[F, A])

(transform: FunctorTransformer[F, G])

(implicit G: Monad[G]): G[A]

Page 68: Why The Free Monad isn't Free

@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

Page 69: Why The Free Monad isn't Free

@kelleyrobinson

// or 'NaturalTransformation'trait FunctorTransformer[F[_], G[_]] { def apply[A](f: F[A]): G[A] }

// Common symbolic operator type ~>[F[_], G[_]] = FunctorTransformer[F, G]

Page 70: Why The Free Monad isn't Free

@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

Page 71: Why The Free Monad isn't Free

@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

Page 72: Why The Free Monad isn't Free

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

Page 73: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

@kelleyrobinson

Evaluating

Applies transformation on `Suspend`

Trampolining for stack safety

Page 74: Why The Free Monad isn't Free

@kelleyrobinson

// or 'NaturalTransformation'trait FunctorTransformer[F[_], G[_]] { def apply[A](f: F[A]): G[A] }

// Common symbolic operator type ~>[F[_], G[_]] = FunctorTransformer[F, G]

Page 75: Why The Free Monad isn't Free

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

}

Page 76: Why The Free Monad isn't Free

@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] }

Page 77: Why The Free Monad isn't Free

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

Page 78: Why The Free Monad isn't Free

@kelleyrobinson

case object ActionTestEvaluator extends FunctorTransformer[Todo, Id] { var actions: List[Todo[String]] = List.empty def apply[A](a: Todo[A]): Id[A]

}

Page 79: Why The Free Monad isn't Free

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

Page 80: Why The Free Monad isn't Free

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

Page 81: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

@kelleyrobinson

Defining multiple interpreters allows you to test side-effecting code without

using testing mocks.

Page 82: Why The Free Monad isn't Free

@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) => ... } }

Page 83: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

@kelleyrobinson

Justifications

• Defer side effects

• Multiple interpreters

• Stack safety

Page 84: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN'T FREE

#BlueSkyScala The path to learning is broken

@kelleyrobinson

Credit: Jessica Kerr

Page 85: Why The Free Monad isn't Free

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

Page 86: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

- Monoids, Functors & Monads

- How to be “Free”

- Why & Why Not “Free”

- Alternatives

- Real World Applications

$

@kelleyrobinson

Page 87: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

@kelleyrobinson

Know your domain

Page 88: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN'T FREE

Functional Spectrum Where does your team fall?

Java Haskell

Page 89: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN'T FREE

Functional Spectrum Where does your team fall?

Java Haskell

Page 90: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

@kelleyrobinson

Alternatives for maintaining stack safety

Page 91: Why The Free Monad isn't Free

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

Page 92: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

@kelleyrobinson

Alternatives for managing side effects

Page 93: Why The Free Monad isn't Free

@kelleyrobinson

import java.sql.ResultSetcase class Person(name: String, age: Int)def getPerson(rs: ResultSet): Person = { val name = rs.getString(1) val age = rs.getInt(2) Person(name, age)}

Page 94: Why The Free Monad isn't Free

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

Page 95: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

- Monoids, Functors & Monads

- How to be “Free”

- Why & Why Not “Free”

- Alternatives

- Real World Applications

$

@kelleyrobinson

Page 96: Why The Free Monad isn't Free

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/

@kelleyrobinsonhttp://www.slideshare.net/jamesskillsmatter/real-world-scalaz

Page 97: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN'T FREE

Examples

• Doobie

• scalaz.concurrent.Task

@kelleyrobinson

https://github.com/tpolecat/doobie

Page 98: Why The Free Monad isn't Free

@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 _ => () }}

Page 99: Why The Free Monad isn't Free

@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] { ... } }

Page 100: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

@kelleyrobinson

My experience... ...what happened?

Page 101: Why The Free Monad isn't Free

WHY THE FREE MONAD ISN’T FREE

- Know your domain

- Use clean abstractions

- Share knowledge

$

@kelleyrobinson

Page 102: Why The Free Monad isn't Free

Thank You! @kelleyrobinson

[email protected]

Page 103: Why The Free Monad isn't Free

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