Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
sealed trait Expression {
type Out
}
object Expression {
type Aux[T] = Expression { type Out = T}
}
case class Const[T](t: T) extends Expression {
override type Out = T
}
case class Field[T](name: String) extends Expression {
override type Out = T
}
sealed abstract class AggExpr[T, U] extends Expression {
val e: Expression.Aux[T]
override type Out = U
}
case class Sum[T](override val e: Expression.Aux[T])(implicit val n: Numeric[T]) extends AggExpr[T, T]
case class Count[T](override val e: Expression.Aux[T]) extends AggExpr[T, Long]
sealed abstract class BiO[T, U, R] extends Expression {
val a: Expression.Aux[T]
val b: Expression.Aux[U]
override type Out = R
}
case class Concat(override val a: Expression.Aux[String], override val b: Expression.Aux[String]) extends BiO[String, String, String]
case class Plus[N](override val a: Expression.Aux[N], override val b: Expression.Aux[N])(implicit val n: Numeric[N]) extends BiO[N, N, N]
object ExprTest {
def eval[R](e: Expression.Aux[R], fs: Map[String, Any] = Map.empty): R = {
e match {
case Const(c) => c
case Field(n) => fs(n).asInstanceOf[R]
case p@Plus(a, b) => p.n.plus(eval(a, fs), eval(b, fs))
case Sum(_) => throw new IllegalArgumentException("sum should not be evaluated")
case Concat(a, b) => (eval(a, fs) + eval(b, fs)).asInstanceOf[R]
case c:Count[_] => 0L.asInstanceOf[R]
}
}
def evalMap[T, U](values: Seq[T], ae: AggExpr[T, U]): Seq[U] = {
ae match {
case Sum(_) => values.asInstanceOf[Seq[U]]
case Count(_) => values.map(_ => 1L)
}
}
def evalReduce[U]( ae: AggExpr[_, U])(a: U, b: U): U = {
ae match {
case s: Sum[_] => s.n.plus(a, b)
case Count(_) => a.asInstanceOf[Long] + b.asInstanceOf[Long]
}
}
def main(args: Array[String]): Unit = {
val e = Plus[Int](Const(42), Field[Int]("fooo"))
println(s"e $e")
val data = Seq(1,2,3,4)
val s = Sum(e)
val c = Count(e)
println("sum = " + evalMap(data, s).reduce(evalReduce(s)))
println("count = " + evalMap(data, c).reduce(evalReduce(c)))
println("eval " + eval(Plus(Const(5), Const(6))))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment