Suppose the elements of an HList
are subclasses of a generic trait. Each element is contained in case class Box[E](elem E)
. That Box
is invariant in E
causes problems with mapping a poly1
over HList
, selecting an element by its parent trait, etc. Here's an example:
import shapeless._
trait Drink[+A]{ def v: A}
case class Water(v: Int) extends Drink[Int]
case class Juice(v: BigDecimal) extends Drink[BigDecimal]
case class Squash(v: BigDecimal) extends Drink[BigDecimal]
case class Box[E](elem: E) // NB! invariance in E
object pour extends Poly1{
implicit def caseInt[A <: Box[Drink[Int]]] = at[A](o => Box(o.elem.v * 2))
implicit def caseDec[A <: Box[Drink[BigDecimal]]] = at[A](o => Box(o.elem.v + 5.0))
}
object Proc {
type I = Box[Water] :: Box[Squash] :: Box[Juice] :: HNil
type O = Box[Int] :: Box[BigDecimal] :: Box[BigDecimal] :: HNil
val drinks: I = Box(Water(10)) :: Box(Squash(15.0)) :: Box(Juice(2.0)) :: HNil
def make()(implicit m: ops.hlist.Mapper.Aux[pour.type, I, O]): O = drinks.map(pour)
}
object Main extends App{
override def main(args: Array[String]): Unit = Proc.make()
}
*The function pour
applies the answer by @Jasper_M to Mapping over HList with subclasses of a generic trait.
This code leads to
Error:(38, 22) could not find implicit value for parameter m: shapeless.ops.hlist.Mapper.Aux[pour.type,Proc.I,Proc.O]
Proc.make()
.
Also, filtering Proc.drinks.covariantFilter[Box[Drink[Int]]]
produces HNil
. (This filter implements the answer by @Travis Brown to Do a covariant filter on an HList.)
Defining Box[+E]
, which solves the problems, is not possible in my project. A naive solution -- to have a case in the pour
for each subclass of Drink
-- does not scale. (This could be made to work by passing monomorphic functions to pour
, which I don't know how.)
Could there be a more sensible approach to mapping or filtering over HLists in this set-up?