Created
April 10, 2017 12:39
-
-
Save boggle/a9064416f060388683a123b91b388820 to your computer and use it in GitHub Desktop.
How to generate extractors using shapeless to simplify pattern matching fixed point types from matryoshka
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.data.Fix | |
import org.opencypher.spark.prototype.api.cyphertype.UnFixable.RecursiveExtractor | |
import matryoshka.Recursive | |
import shapeless.ops.hlist.Tupler | |
import scala.language.higherKinds | |
import scala.reflect.ClassTag | |
import scalaz.Functor | |
object UnFixable { | |
import shapeless._ | |
trait Extractor[A] { | |
type Out | |
def unapply(v: A): Option[Out] | |
} | |
object Extractor { | |
type Aux[T, R] = Extractor[T] { type Out = R } | |
def apply[T, R](implicit extractor: Aux[T, R]): Aux[T, R] = extractor | |
} | |
final class RecursiveExtractor[Re, T[_] <: F[_], F[_]](implicit aux: Recursive.Aux[Re, F], func: Functor[F]) { | |
def tuple[R <: HList, O] | |
(implicit | |
tag: ClassTag[T[Re]], | |
gen: Generic[T[Re]] {type Repr = R}, | |
tupler: Tupler[R] {type Out = O} | |
) | |
: Extractor.Aux[Re, O] = new Extractor[Re] { | |
override type Out = O | |
override def unapply(t: Re): Option[O] = tag.unapply(aux.project(t)).map(v => gen.to(v).tupled) | |
} | |
def single[O] | |
(implicit | |
tag: ClassTag[T[Re]], | |
gen: Generic[T[Re]] {type Repr = O :: HNil} | |
) | |
: Extractor.Aux[Re, O] = new Extractor[Re] { | |
override type Out = O | |
override def unapply(t: Re): Option[O] = tag.unapply(aux.project(t)).map(v => gen.to(v).head) | |
} | |
} | |
object RecursiveExtractor { | |
def apply[Re, T[_] <: F[_], F[_]](implicit aux: Recursive.Aux[Re, F], func: Functor[F]) = | |
new RecursiveExtractor[Re, T, F] | |
} | |
} | |
object Main { | |
sealed trait Expr[A] { | |
def name = toString | |
} | |
final case class Add[A](l: A, r: A) extends Expr[A] | |
final case class Mul[A](l: A, r: A) extends Expr[A] | |
final case class Pow[A](l: A, exp: Int) extends Expr[A] | |
final case class Lit[A](v: Int) extends Expr[A] | |
object Expr { | |
implicit val functor = new Functor[Expr] { | |
override def map[A, B](fa: Expr[A])(f: (A) => B): Expr[B] = fa match { | |
case Add(l, r) => Add(f(l), f(r)) | |
case Mul(l, r) => Mul(f(l), f(r)) | |
case Pow(l, expr) => Pow(f(l), expr) | |
case Lit(v) => Lit(v) | |
} | |
} | |
} | |
type ExprF = Fix[Expr] | |
val AddF = RecursiveExtractor[ExprF, Add, Expr].tuple | |
val MulF = RecursiveExtractor[ExprF, Mul, Expr].tuple | |
val PowF = RecursiveExtractor[ExprF, Pow, Expr].tuple | |
val LitF = RecursiveExtractor[ExprF, Lit, Expr].single[Int] | |
def main(args: Array[String]): Unit = { | |
val v1: ExprF = Fix(Add(Fix(Lit(1)), Fix(Lit(2)))) | |
val v2: ExprF = Fix(Mul(v1, v1)) | |
val v3: ExprF = Fix(Pow(v2, 2)) | |
v3 match { | |
case PowF(MulF(AddF(LitF(a), LitF(b)), AddF(LitF(c), LitF(d))), exp) => | |
println(Math.pow((a + b) * (c + d), exp)) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment