Skip to content

Instantly share code, notes, and snippets.

@kelsey-sorrels
Last active January 19, 2018 12:41
Show Gist options
  • Save kelsey-sorrels/674aaca9417da9cbb6b2a7ec673e1344 to your computer and use it in GitHub Desktop.
Save kelsey-sorrels/674aaca9417da9cbb6b2a7ec673e1344 to your computer and use it in GitHub Desktop.
Shapeless Recursive Coproduct
import matryoshka._
import matryoshka.data._
import matryoshka.implicits._
import shapeless._
type SF[A] = Boolean :+: Int :+: String :+: List[A] :+: Map[String, A] :+: CNil
val v0 = Coproduct[SF[Nothing]](1)
println(v0) // 1
val v1 = Coproduct[SF[Nothing]](List.empty)
println(v1) // List()
val v2 = Coproduct[SF[SF[Nothing]]](List(Coproduct[SF[Nothing]](1)))
println(v2) // List(1)
val v3 = Coproduct[SF[SF[Nothing]]](List(Coproduct[SF[Nothing]](List.empty)))
println(v3) // List(List())
// how many layers of recursion are you on
val v4 = Coproduct[SF[SF[SF[Nothing]]]](List(Coproduct[SF[SF[Nothing]]](List(Coproduct[SF[Nothing]](1)))))
println(v4) // List(List(1))
// like,, maybe 5, or 6 right now. my dude
// you are like a little baby
// watch this
type S = Fix[SF]
object S {
def apply(b: Boolean): S =
Fix(Coproduct[SF[Fix[SF]]](b))
def apply(i: Int): S =
Fix(Coproduct[SF[Fix[SF]]](i))
def apply(s: String): S =
Fix(Coproduct[SF[Fix[SF]]](s))
def apply(l: List[S]): S =
Fix(Coproduct[SF[Fix[SF]]](l))
def apply(m: Map[String, S]): S =
Fix(Coproduct[SF[Fix[SF]]](m))
}
println(S(1)) // Fix(1)
println(S(List.empty)) // Fix(List())
println(S(List(S(1)))) // Fix(List(Fix(1)))
println(S(List(S(List.empty)))) // Fix(List(Fix(List())))
println(S(List(S(List(S(1)))))) // Fix(List(Fix(List(Fix(1)))))
import scalaz.Functor
implicit val sFunctor = new scalaz.Functor[SF] {
override def map[A, B](fa: SF[A])(f: (A) => B):SF[B] = fa match {
// Boolean :+: Int :+: String :+: List[A] :+: Map[String, A]
case Inl(b) => Inl(b)
case Inr(Inl(i)) => Inr(Inl(i))
case Inr(Inr(Inl(s))) => Inr(Inr(Inl(s)))
case Inr(Inr(Inr(Inl(l)))) => Inr(Inr(Inr(Inl(l.map(f)))))
case Inr(Inr(Inr(Inr(Inl(l))))) => Inr(Inr(Inr(Inr(Inl(l.mapValues(f))))))
}
}
// Add all ints evaulator
val addInts: Algebra[SF, Int] = {
case Inl(b) => 0
case Inr(Inl(i)) => i
case Inr(Inr(Inl(s))) => 0
case Inr(Inr(Inr(Inl(l)))) => l.foldLeft[Int](0)(_ + _)
case Inr(Inr(Inr(Inr(Inl(m))))) => m.values.foldLeft[Int](0)(_ + _)
}
val s = S(Map(
"a" -> S(2),
"b" -> S(List(S(true), S(List(S(2), S("3"), S(4)))))))
val r = s.cata(addInts)
println(r) // 8
// compact print evaluator
val compactPrint: Algebra[SF, String] = {
case Inl(b) => if (b) "true" else "false"
case Inr(Inl(i)) => i.toString
case Inr(Inr(Inl(s))) => "\"" + s + "\""
case Inr(Inr(Inr(Inl(l)))) =>
val sep = ", "
s"[${l.mkString(sep)}]"
case Inr(Inr(Inr(Inr(Inl(m))))) =>
val sep = ", "
val inner = m.map { case (k, v) => s"$k: $v" }.mkString(sep)
s"{$inner}"
}
val rstr = s.cata(compactPrint)
println(rstr) // {a: 2, b: [true, [2, "3", 4]]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment