Skip to content

Instantly share code, notes, and snippets.

@chenharryhua
Last active July 27, 2016 05:56
Show Gist options
  • Save chenharryhua/d19a334174278bc699b49a817b1a24b7 to your computer and use it in GitHub Desktop.
Save chenharryhua/d19a334174278bc699b49a817b1a24b7 to your computer and use it in GitHub Desktop.
package recursion.scheme
import scalaz.Functor
//http://blog.sumtypeofway.com/recursion-schemes-part-iii-folds-in-context/
object Part1 {
sealed trait Expr[A]
case class Ident[A](name: String) extends Expr[A]
case class Index[A](target: A, idx: A) extends Expr[A]
case class Call[A](func: A, args: List[A]) extends Expr[A]
case class Unary[A](op: String, target: A) extends Expr[A]
case class Binary[A](lhs: A, op: String, rhs: A) extends Expr[A]
case class Paren[A](target: A) extends Expr[A]
case class Literal[A](intVal: Int) extends Expr[A]
implicit def exprFunctor = new Functor[Expr] {
def map[A, B](fa: Expr[A])(f: A => B): Expr[B] = fa match {
case Index(fst, snd) => Index(f(fst), f(snd))
case Call(a, as) => Call(f(a), as.map(f))
case Unary(s, a) => Unary(s, f(a))
case Binary(a, s, b) => Binary(f(a), s, f(b))
case Paren(a) => Paren(f(a))
case Literal(a) => Literal(a).asInstanceOf[Expr[B]]
case Ident(a) => Ident(a).asInstanceOf[Expr[B]]
}
}
case class Fix[F[_]](out: F[Fix[F]])
def bottomUp[F[_]](fn: Fix[F] => Fix[F])(a: Fix[F])(implicit F: Functor[F]): Fix[F] =
fn(Fix(F.map(a.out) { x => bottomUp(fn)(x) }))
def topDown[F[_]](fn: Fix[F] => Fix[F])(a: Fix[F])(implicit F: Functor[F]): Fix[F] =
Fix(F.map(fn(a).out) { x => topDown(fn)(x) })
def flattenFix(a: Fix[Expr]): Fix[Expr] = a match {
case Fix(Paren(o)) => o
case _ => a
}
val flatten = bottomUp(flattenFix)(_)
}
object Part2 {
import Part1._
type Algebra[F[_], A] = F[A] => A
def cata[F[_], A](alg: Algebra[F, A], fix: Fix[F])(implicit F: Functor[F]): A =
alg(F.map(fix.out)(cata(alg, _)))
type CoAlgebra[F[_], A] = A => F[A]
def ana[F[_], A](coalg: CoAlgebra[F, A], a: A)(implicit F: Functor[F]): Fix[F] =
Fix(F.map(coalg(a)) { ana(coalg, _) })
def bottomUp2[F[_]](fn: Fix[F] => Fix[F])(a: Fix[F])(implicit F: Functor[F]): Fix[F] =
cata((x: F[Fix[F]]) => fn(Fix(x)), a)
}
object Part3 {
import Part1._
type RAlgebra[F[_], A] = F[(Fix[F], A)] => A
def para[F[_], A](r: RAlgebra[F, A], fix: Fix[F])(implicit F: Functor[F]): A = {
def fanout(f: Fix[F]): (Fix[F], A) = (f, para(r, f))
r(F.map(fix.out)(fanout))
}
type RCoAlgebra[F[_], A] = A => F[Either[Fix[F], A]]
def apo[F[_], A](rc: RCoAlgebra[F, A], a: A)(implicit F: Functor[F]): Fix[F] = {
def fanin(in: Either[Fix[F], A]): Fix[F] = in match {
case Left(l) => l
case Right(r) => apo(rc, r)
}
Fix(F.map(rc(a)) { x => fanin(x) })
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment