Skip to content

Instantly share code, notes, and snippets.

@shajra
Created July 31, 2013 01:54
Show Gist options
  • Save shajra/6118699 to your computer and use it in GitHub Desktop.
Save shajra/6118699 to your computer and use it in GitHub Desktop.
making Free and then a list with it
package learning
trait Functor[F[_]] {
def map[A,B](a: F[A])(f: A => B): F[B]
}
trait Monad[M[_]] extends Functor[M] {
def point[A](a: A): M[A]
def flatMap[A,B](a: M[A])(f: A => M[B]): M[B]
}
abstract class Free[F[_]: Functor, A] {
def resume: Either[A, F[Free[F, A]]]
def map[B](f: A => B): Free[F, B] =
implicitly[Monad[({type λ[a] = Free[F, a]})#λ]].map(this)(f)
def flatMap[B](f: A => Free[F,B]): Free[F, B] =
implicitly[Monad[({type λ[a] = Free[F, a]})#λ]].flatMap(this)(f)
}
case class Done[F[_]: Functor, A](a: A) extends Free[F, A] {
def resume = Left(a)
}
case class More[F[_]: Functor, A](k: F[Free[F,A]]) extends Free[F, A] {
def resume = Right(k)
}
object Free extends App {
implicit def freeMonad[F[_]](implicit F: Functor[F])
: Monad[({type λ[a] = Free[F, a]})#λ] = {
type M[a] = Free[F, a]
new Monad[M] {
def point[A](a: A): M[A] = Done(a)
def map[A,B](a: M[A])(f: A => B): M[B] =
a match {
case Done(a) => Done(f(a))
case More(c) => More(F.map(c) { map(_)(f) })
}
def flatMap[A,B](a: M[A])(f: A => M[B]): M[B] =
a match {
case Done(a) => f(a)
case More(c) => More(F.map(c) { flatMap(_)(f) })
}
}
}
implicit def freeListFunctorLeft[A]
: Functor[({type λ[a] = (A, a)})#λ] = {
type F[O] = (A, O)
new Functor[F] {
def map[B,C](a: F[B])(f: B => C): F[C] = (a._1, f(a._2))
}
}
type FreeList[A] =
Free[({type λ[a] = (A, a)})#λ, Unit]
def nil[A]: FreeList[A] =
Done[({type λ[a] = (A, a)})#λ, Unit](())
def cons[A](a: A, as: FreeList[A]): FreeList[A] =
More[({type λ[a] = (A, a)})#λ, Unit]((a, as))
val exampleFreeList: FreeList[Int] =
cons(1, cons(2, cons(3, nil)))
def functorLeft[A] = implicitly[Functor[({type F[aa] = (A, aa)})#F]]
def toList[A](fl: FreeList[A]): List[A] =
fl.resume match {
case Left(_) => Nil
case Right((a, as)) => a :: toList(as)
}
// just seeing what happens in a for-comprehension; I'm getting this:
//
// List(1, 2, 3, 1, 2, 3)
//
println(toList(for(a <- exampleFreeList; b <- exampleFreeList) yield ()))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment