Skip to content

Instantly share code, notes, and snippets.

@afsalthaj
Last active November 21, 2019 07:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save afsalthaj/701e86eade05f683aed0e96fa53dccad to your computer and use it in GitHub Desktop.
Save afsalthaj/701e86eade05f683aed0e96fa53dccad to your computer and use it in GitHub Desktop.
object RecursionSchemes extends App {
import PropertyTreeX._
sealed trait PropertyTreeX[+K, +V, +A]
object PropertyTreeX {
final case object EmptyX extends PropertyTreeX[Nothing, Nothing, Nothing]
final case class LeafX[+V](value: V) extends PropertyTreeX[Nothing, V, Nothing]
final case class RecordX[K, +A](value: Map[K, A]) extends PropertyTreeX[K, Nothing, A]
}
final case class Fix[F[_]](unfix: F[Fix[F]])
def cata[F[_], A](f: F[A] => A)(implicit F: Functor[F]): Fix[F] => A =
fix => f(F.map(fix.unfix)(cata(f)))
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
object Functor {
implicit def functorInstance[K, V]: Functor[PropertyTreeX[K, V, ?]] = new Functor[PropertyTreeX[K, V, ?]] {
override def map[A, B](sa: PropertyTreeX[K, V, A])(f: A => B): PropertyTreeX[K, V, B] =
sa match {
case EmptyX => EmptyX
case LeafX(v) => LeafX(v)
case RecordX(value) => RecordX(value.view.mapValues(f).toMap)
}
}
}
def empty(): Fix[PropertyTreeX[Nothing, Nothing, ?]] =
Fix[PropertyTreeX[Nothing, Nothing, ?]](EmptyX)
def record[K, V](value: Map[K, Fix[PropertyTreeX[K, V, ?]]]): Fix[PropertyTreeX[K, V, ?]] =
Fix[PropertyTreeX[K, V, ?]](RecordX(value))
def leaf[K, V](value: V): Fix[PropertyTreeX[K, V, ?]] =
Fix[PropertyTreeX[K, V, ?]](LeafX(value))
// Quite a simple recursion that doesn't worry about the structure of V, however, V itself is PropertyTree
def propertyAccumulator[K, V](zero: V)(f: (V, V) => V): PropertyTreeX[K, V, V] => V = {
case EmptyX => zero
case LeafX(value) => value
case RecordX(map) => map.view.values.fold(zero)(f)
}
val result =
cata(propertyAccumulator[String, String]("")(_ + _))
val property: Fix[PropertyTreeX[String, String, ?]] =
record(
Map(
"string" ->
record(
Map("string2" -> record(Map("string3" -> leaf("value"))))
),
"anotherstring" ->
record(
Map("string2" -> record(Map("string3" -> leaf("value2"))))
)
)
)
// Converting property tree to its fixed type is easy.
val res = result(property)
println(res)
// convert a Map[Vector[K], V] to PropertyTree[K, V, A]
// Convert a PropertyTree[K, V, A] to Map[Vector[K], V, A]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment