Reputation: 161
I'm playing with type classes in Scala 3, and got to a compilation error that I can't explain.
Considering the following code:
trait Transformation[Input, Output <: Tuple]:
def apply(x: Input): Output
trait ListOfTransformations[T[_, _] <: Transformation[_, _], Input <: Tuple, Output <: Tuple] extends Transformation[Input, Output]
object ListOfTransformations:
given empty[T[_, _] <: Transformation[_, _]]: ListOfTransformations[T, EmptyTuple, EmptyTuple] with
def apply(t: EmptyTuple): EmptyTuple = t
given nonEmpty[T[_, _] <: Transformation[_, _], Head, Tail <: Tuple, HeadOutput <: Tuple, TailOutput <: Tuple](
using
ht: T[Head, HeadOutput],
tt: ListOfTransformations[T, Tail, TailOutput]
): Transformation[Head *: Tail, Tuple.Concat[HeadOutput, TailOutput]] with
def apply(x: Head *: Tail): Tuple.Concat[HeadOutput, TailOutput] = ht(x.head) ++ tt(x.tail)
I get:
Found: Tuple.Head[Head² *: Tail]
Required: nonEmpty.this.ht.Input
where: Head is a type in object Tuple which is an alias of [X <: NonEmptyTuple] =>>
X match {
case [x, _ <: Tuple] =>> scala.runtime.MatchCase[x *: _, x]
}
Head² is a type in class nonEmpty
Tail is a type in class nonEmpty with bounds <: Tuple
What am I missing?
Upvotes: 3
Views: 96
Reputation: 7604
When taking type constructors with bounds as type parameters, make sure you use actual arguments instead of wildcards. Using T[a, b] <: Transformation[a, b]
instead of T[_, _] <: Transformation[_, _]
lets it compile (Scastie). The former takes a type constructor that, when given two types, gives a type that is a subtype of Transformation[a, b]
for some a
and b
that we don't know. By not using wildcards (and ignoring the actual parameters of T
), you're letting the compiler know precisely what a T[a, b]
is a subtype of.
Upvotes: 2