Reactormonk Reactormonk - 2 months ago 10
Scala Question

Transitive LUB?

What needs to be changed in this snippet that it compiles?

import shapeless._
import LUBConstraint._
import ops.hlist.Prepend

class Foo[L <: HList: <<:[Int]#λ](val l: L) {
def ++[H <: HList: <<:[Int]#λ](h: H)(implicit prepend: Prepend[L, H]) = {
new Foo(l ::: h)
}
}


Currently:

could not find implicit value for evidence parameter of type shapeless.LUBConstraint[prepend.Out,Int]

Answer

Good question ... you were very close :-)

The problem is that, even though it's obvious to us, the Scala compiler isn't able to infer that the concatenation of two HLists of Int elements is an HList of Int elements. We can help it by pulling out the type of the concatenation into a type variable (Out, note the use of the Prepend.Aux type alias to constrain this new type variable) and then asking it to prove directly that Out has the required property (by requiring evidence of the shape of Out),

import shapeless._
import ops.hlist.Prepend
import LUBConstraint._

class Foo[L <: HList: <<:[Int]#λ](val l: L) {
  def ++[H <: HList: <<:[Int]#λ, Out <: HList](h: H)
    (implicit prepend: Prepend.Aux[L, H, Out], ev: LUBConstraint[Out, Int]) = {
      new Foo(l ::: h)
    }
}