What does the Aux pattern accomplish in Scala?

后端 未结 1 2002
生来不讨喜
生来不讨喜 2021-01-18 16:23

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

相关标签:
1条回答
  • 2021-01-18 17: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".

    0 讨论(0)
提交回复
热议问题