What does the Aux pattern accomplish in Scala?

旧城冷巷雨未停 提交于 2019-12-01 18:18:10

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".

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!