Created
September 30, 2020 14:46
-
-
Save limansky/b70ae6ddd26c127970caf719ffbefaec to your computer and use it in GitHub Desktop.
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
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