Skip to content

Instantly share code, notes, and snippets.

@slouc
Created May 2, 2017 19:40
Show Gist options
  • Save slouc/3c9146aa55ad2c2a5ebf5342f177d9c2 to your computer and use it in GitHub Desktop.
Save slouc/3c9146aa55ad2c2a5ebf5342f177d9c2 to your computer and use it in GitHub Desktop.
Free Monad
import scalaz.Monad
import scalaz._
sealed trait Free[F[_], A] {
def pure(a: A): Free[F, A] = Free.Pure(a)
def lift(f: F[A]): Free[F, A] = Free.Suspend(f)
def flatMap[B](f: A => F[B]): Free[F, B] = Free.Bind[F, A, B](this, f)
def foldMap[G[_] : Monad, E](nt: F ~> G): G[A] = this match {
case Free.Pure(a) => Monad[G].pure(a)
case Free.Suspend(fa) => nt(fa)
case bind: Free.Bind[F, E, A] => // in order to fix the types, otherwise Bind[F, Any]
Monad[G].bind(bind.target.foldMap(nt)) {
(e: E) => lift(bind.f(e)).foldMap(nt)
}
}
}
object Free {
final case class Pure[F[_], A](a: A) extends Free[F, A]
final case class Suspend[F[_], A](fa: F[A]) extends Free[F, A]
final case class Bind[F[_], A, B](target: Free[F, A], f: A => F[B]) extends Free[F, B]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment