In my understanding the following two functions and their calls should be identical:
def f1[L1 <: HList, L2](xs: L1)(implicit sequencer: Sequencer.Aux[L1, Option, L2]) {
println(xs.sequence)
}
def f2[L1 <: HList : Sequencer.Aux[*, Option, L2], L2](xs: L1) {
println(xs.sequence)
}
f1[Option[Int] :: Option[String] :: HNil, Int :: String :: HNil](Some(42) :: Some("foo") :: HNil)
f2[Option[Int] :: Option[String] :: HNil, Int :: String :: HNil](Some(42) :: Some("foo") :: HNil)
However, the call to f2 doesn't compile:
could not find implicit value for evidence parameter of type cats.sequence.Sequencer[Option[Int] :: Option[String] :: shapeless.HNil]{type F[X] = Option[X]; type LOut = Int :: String :: shapeless.HNil}
The Scala compile seems to expand the type alias Sequencer.Aux in the second case and isn't able to construct a suitable implicit.
If I directly define my function with the expanded type, no implicit can be constructed either:
def f3[L1 <: HList, L2](xs: L1)(implicit sequencer: Sequencer[L1]{type F[X] = Option[X]; type LOut = L2}) {
println(xs.sequence)
}
Apart from the inconvenience of not being able to use the more compact context bound syntax there are two things that I don't understand about this situation:
- why is the type of the evidence implicit only expanded if i use the context bound syntax? (and are there more semantical differences between the two syntaxes?)
- why is Scala unable to construct a suitable implicit for the expanded case? After all, Sequencer.Aux is only a type alias defined like this:
type Aux[L <: HList, F0[_], LOut0] = Sequencer[L] {
type F[X] = F0[X]
type LOut = LOut0
}
I would have expected both types to behave identical.