Search code examples
scalagenericstypeclassimplicitshapeless

Shapeless HList return type


I am trying to incorporate a bit of shapeless into my code and am falling at an embarassingly early hurdle. In the example below, it seems that HCons-ing an undefined object to an HNil:

trait HasValue[A, B] {
  def get(a: A): B
  def getAll[L <: HList, O <: HList](a: A)(implicit ga: GetAll[A, L]): O = ga.getAll(a, HNil)
}

trait GetAll[A, B] {
  def getAll[L <: HList, O <: HList](a: A, l: L): O
}
implicit def getAllIfHasValue[A, B](implicit ev: HasValue[A, B]) = new GetAll[A, B] {
  def getAll[L <: HList, O <: HList](a: A, l: L): O = ev.get(a) :: l
}

and getting an error - type mismatch: Found B :: L, Required O. I would have thought that, since L is itself an HList, B :: L should itself be an HList and therefore all should be well. But obviously not.

Any help appreciated!


Solution

  • I guess the error is pretty clear

    type mismatch;
     found   : B :: L
     required: O
    

    ev.get(a) :: l has type B :: L but O is expected.

    I would have thought that, since L is itself an HList, B :: L should itself be an HList and therefore all should be well.

    B :: L is an HList, indeed. The problem is that B :: L is not O.

    And when you write the signature

    def getAll[L <: HList, O <: HList](a: A, l: L): O = ???
    

    this means, for any type L <: HList and any type O <: HList, having values a: A and l: L produce a value of type O. I guess that's not what you wanted.

    Maybe you wanted to return a type O depending on types A, B. Then you can introduce a type parameter

    trait GetAll[A, B] {
      type O
      def getAll[L <: HList](a: A, l: L): O
    }
    

    Or maybe you wanted to return a type O depending on types A, B, L <: HList. Then additionally you should transfer L to the trait level

    trait GetAll[A, B, L <: HList] {
      type O
      def getAll(a: A, l: L): O
    }