I have a bit of a sense of the Aux pattern (as used in shapeless and elsewhere) in which a type member is extracted into a type parameter, and I know it\'s a workaround the
Simply speaking this pattern lets you establish a relation between two generic type parameters.
Let's take a look at shapeless' LabelledGeneric type class which gives you a generic HList representation for case classes:
trait LabelledGeneric[T] {
type Repr
}
T is the input type, i.e LabelledGeneric[MyCaseClass] will give you the HList representation of MyCaseClass. Repr is the output type, i.e. the HList type corresponding to T.
Let's write a method that takes a Generic instance and needs another parameter of the output type. For instance we could use Keys to collect the field names of a labelled generic
def fieldNames[T](implicit gen: LabelledGeneric[T], keys: Keys[gen.Repr]): keys.Repr …
Except that this doesn't work because Scala doesn't let you access gen or keys here. We can either have a concrete type or a type variable.
And that's where Aux comes into play: It let's us "lift" gen.Repr into a type variable:
object Generic {
type Aux[T, Repr0] = Generic[T] { type Repr = Repr0 }
}
As you can see the Aux type gives us a way from Repr to a type variable, so we can finally define foo:
def foo[T, Repr, K](
implicit gen: LabelledGeneric.Aux[T, Repr],
keys: Keys.Aux[Repr, K]
): K …
If you are familiar with Prolog you can read Aux as a predicate that proves a relation between two type variables. In the above example you can read it as "LabelledGeneric proves that Repr is the generic representation with labels of T, and Keys.Aux proves that K is a list of all keys of Repr".