A pedagogical free(er) monad in 23 lines of Scala
sealed trait Free[F[_], A] { self => | |
final def map[B](ab: A => B): Free[F, B] = Free.flatMap(self, ab andThen (Free.point[F, B](_))) | |
final def flatMap[B](afb: A => Free[F, B]): Free[F, B] = Free.flatMap(self, afb) | |
final def interpret[G[_]: Monad](fg: F ~> G): G[A] = self match { | |
case Free.Point(a0) => a0().point[G] | |
case Free.Effect(fa) => fg(fa) | |
case fm : Free.FlatMap[F, A] => | |
val ga0 = fm.fa.interpret[G](fg) | |
ga0.flatMap(a0 => fm.afb(a0).interpret[G](fg)) | |
} | |
} | |
object Free { | |
def point[F[_], A](a: => A): Free[F, A] = Point[F, A](() => a) | |
def liftF[F[_], A](fa: F[A]): Free[F, A] = Effect[F, A](fa) | |
private final case class Point[F[_], A](a0: () => A) extends Free[F, A] | |
private final case class Effect[F[_], A](fa: F[A]) extends Free[F, A] | |
private sealed trait FlatMap[F[_], B] extends Free[F, B] { | |
type A; def fa: Free[F, A]; def afb: A => Free[F, B] | |
} | |
private def flatMap[F[_], A0, B](fa0: Free[F, A0], afb0: A0 => Free[F, B]): FlatMap[F, B] = new FlatMap[F, B] { | |
type A = A0; def fa = fa0; def afb = afb0 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment