Skip to content

Instantly share code, notes, and snippets.

@arturaz
Last active September 21, 2021 21:05
Show Gist options
  • Save arturaz/7833ed7764f72653e539cc314b3fae58 to your computer and use it in GitHub Desktop.
Save arturaz/7833ed7764f72653e539cc314b3fae58 to your computer and use it in GitHub Desktop.
package app
import shapeless.ops.hlist.{ConstMapper, Mapper, ZipWith}
import shapeless.{::, HList, HNil, Poly2}
case class Params()
sealed trait EvaluatableGeneratorFilter[+Result] {
def eval(p: Params): Result
}
case class FilteredValue[A, Filters <: HList, Interim <: HList, Outputs <: HList](
filters: Filters
)(private val f: Outputs => A)(
implicit
constMapper: ConstMapper.Aux[Params, Filters, Interim],
zipWith: ZipWith.Aux[Filters, Interim, FilteredValue.evalPoly.type, Outputs]
) {
def eval(p: Params): A = {
val mapped = filters.zipWith(filters.mapConst(p))(FilteredValue.evalPoly)
f(mapped)
}
def map[B](
// Needs to have different name than mapper, otherwise implicit resolution fails...
resultMapper: A => B
): FilteredValue[B, Filters, Interim, Outputs] =
FilteredValue[B, Filters, Interim, Outputs](filters) { a =>
resultMapper(f(a))
}
}
object FilteredValue {
object evalPoly extends Poly2 {
implicit def `case`[T]: Case.Aux[EvaluatableGeneratorFilter[T], Params, T] = at(_.eval(_))
}
case class Builder[
Filters <: HList, Interim <: HList, Outputs <: HList
](filters: Filters)(implicit
constMapper: ConstMapper.Aux[Params, Filters, Interim],
zipWith: ZipWith.Aux[Filters, Interim, FilteredValue.evalPoly.type, Outputs]
) {
def build[A](f: Outputs => A) = FilteredValue[A, Filters, Interim, Outputs](filters)(f)
}
def constant[A](a: A): FilteredValue[A, HNil, HNil, HNil] = FilteredValue(HNil: HNil) { _ => a }
}
object Test {
val test =
new EvaluatableGeneratorFilter[Int] { def eval(p: Params) = 3 } ::
new EvaluatableGeneratorFilter[String] { def eval(p: Params) = "3" } :: HNil
test.zipWith(test.mapConst(Params()))(FilteredValue.evalPoly)
val res2 = FilteredValue.Builder(test).build { case a :: b :: HNil => b * a }.eval(Params())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment