Understanding the Aux pattern in Scala Type System
scala, shapeless
Solution
Imagine a typeclass for getting the last element of any tuple.
trait Last[A] {
type B
def last(a: A): B
}
object Last {
type Aux[A,B0] = Last[A] { type B = B0 }
implicit def tuple1Last[A]: Aux[Tuple1[A],A] = new Last[Tuple1[A]] {
type B = A
def last(a: Tuple1[A]) = a._1
}
implicit def tuple2Last[A,C]: Aux[(A,C),C] = new Last[(A,C)] {
type B = C
def last(a: (A,C)) = a._2
}
...
}
The type `B` always depends on the type `A`, that's why `A` is an input type of the typeclass and `B` is an output type.
Now if you want a function that can sort any list of tuples based on the last element you need access to the `B` type in the same argument list. That's the main reason, in the current state of Scala, why you need the `Aux` pattern: currently it's not possible to refer to the `last.B` type in the same parameter list as where `last` is defined, nor is it possible to have multiple implicit parameter lists.
def sort[A,B](as: List[A])(implicit last: Last.Aux[A,B], ord: Ordering[B]) = as.sortBy(last.last)
Of course you can always write `Last[A] { type B = B0 }` out in full, but obviously that becomes very impractical very quickly (imagine adding a couple more implicit parameters with dependent types, something that's very common with Shapeless); that's where the `Aux` type alias comes in.
Problem
This question may be asked and answered before, but I would like to understand this with an example and I could not reason out where the Aux pattern might be helpful! So here is the trait: ``` trait Foo[A] { type B def value: B } ``` Why do I have a type that is kind of bound to the return type of the value function? What do I achieve doing this? In particular, where would I use such patterns?