Il y a deux questions distinctes ici:
- Pourquoi n'Informe du type d'utilisation des membres au lieu des paramètres de type, dans certains cas, dans certaines classes de type?
- Pourquoi n'Informe comprennent
Aux
type d'alias dans le compagnon des objets de ces classes de type?
Je vais commencer par la deuxième question parce que la réponse est plus simple: l' Aux
type d'alias sont entièrement syntaxique, commodité. Vous ne jamais avoir à les utiliser. Par exemple, supposons que nous voulions écrire une méthode qui vous permettra de compilation uniquement lorsqu'elle est appelée avec deux les hlist qui ont la même longueur:
import shapeless._, ops.hlist.Length
def sameLength[A <: HList, B <: HList, N <: Nat](a: A, b: B)(implicit
al: Length.Aux[A, N],
bl: Length.Aux[B, N]
) = ()
L' Length
type classe a un paramètre de type (pour l' HList
type) et un type de membre (pour l' Nat
). L' Length.Aux
de la syntaxe, il est relativement facile de se référer à l' Nat
type de membre dans le paramètre implicite de la liste, mais c'est juste une commodité-ce qui suit est exactement l'équivalent:
def sameLength[A <: HList, B <: HList, N <: Nat](a: A, b: B)(implicit
al: Length[A] { type Out = N },
bl: Length[B] { type Out = N }
) = ()
L' Aux
version a quelques avantages par rapport à l'écriture du type améliorations dans ce sens: c'est moins bruyant, et il ne nécessite pas de nous rappeler le nom de la membre de type. Ces derniers sont purement ergonomique questions, même si-l' Aux
des alias de rendre notre code plus facile à lire et à écrire, mais ils ne changent pas ce que nous pouvons ou ne pouvons pas faire avec le code de façon significative.
La réponse à la première question est un peu plus complexe. Dans de nombreux cas, y compris mon sameLength
, il n'y a aucun avantage à en Out
être un membre de type au lieu d'un paramètre de type. Parce que Scala ne pas permettre à plusieurs paramètre implicite sections, nous avons besoin d' N
être un paramètre de type pour notre méthode, si nous voulons vérifier que les deux Length
des cas ont le même Out
type. À ce stade, l' Out
sur Length
pourrait aussi bien être un paramètre de type (au moins de notre point de vue que les auteurs de l' sameLength
).
Dans d'autres cas, cependant, nous pouvons tirer avantage du fait que Informes parfois (je vais en parler plus précisément où dans un instant) utilise le type de membres au lieu des paramètres de type. Par exemple, supposons que nous voulions écrire une méthode qui retourne une fonction qui vous permet de convertir un cas spécifié le type de classe en HList
:
def converter[A](implicit gen: Generic[A]): A => gen.Repr = a => gen.to(a)
Maintenant, nous pouvons l'utiliser comme ceci:
case class Foo(i: Int, s: String)
val fooToHList = converter[Foo]
Et nous allons avoir une belle Foo => Int :: String :: HNil
. Si Generic
s' Repr
ont un type de paramètre à la place d'un membre de type, il faudrait écrire quelque chose comme ceci à la place:
// Doesn't compile
def converter[A, R](implicit gen: Generic[A, R]): A => R = a => gen.to(a)
Scala ne prend pas en charge partielle de l'application de paramètres de type, de sorte que chaque fois que nous appelons le présent (hypothétique) de la méthode que nous aurions à spécifier à la fois les paramètres de type puisque nous voulons spécifier A
:
val fooToHList = converter[Foo, Int :: String :: HNil]
De ce fait, il fondamentalement sans valeur, puisque le but était de permettre au générique de machines de comprendre la représentation.
En général, quand un type est déterminée de manière unique par un type de la classe d'autres paramètres, Informe permettra d'en faire un membre de type au lieu d'un paramètre de type. Tous les cas de classe a qu'une seule représentation générique, de sorte Generic
a un paramètre de type (pour le cas type de classe) et un type de membre (pour le type de représentation); chaque HList
a une seule longueur, Length
a un paramètre de type et un type de membre, etc.
Faire unique qui a déterminé les types de type de membres au lieu des paramètres de type signifie que si nous voulons les utiliser uniquement comme des chemin des types dépendants (comme dans le premier converter
ci-dessus), nous pouvons, mais si nous voulons les utiliser comme si elles étaient les paramètres de type, nous pouvons toujours écrire soit le type de raffinement (ou la plus agréable du point de vue syntaxique Aux
version). Si Informes fait ces types de paramètres de type dès le début, il ne serait pas possible d'aller dans la direction opposée.
Comme une note de côté, cette relation entre un type de classe de type "paramètres" (j'utilise des guillemets car ils ne peuvent être des paramètres dans le littéral Scala sens) est appelée une "dépendance fonctionnelle" dans des langages comme Haskell, mais vous ne devriez pas sentir comme vous avez besoin de comprendre quoi que ce soit sur les dépendances fonctionnelles en Haskell pour obtenir ce qu'il se passe en Informe.