Last active
January 19, 2018 12:41
-
-
Save kelsey-sorrels/674aaca9417da9cbb6b2a7ec673e1344 to your computer and use it in GitHub Desktop.
Shapeless Recursive Coproduct
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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