Permettez-moi de compenser le début d'une partie de cette confusion en insistant avec une certaine ambiguïté. J'aime utiliser l'analogie avec le niveau de valeur pour expliquer cela, car les gens ont tendance à être plus familiers avec cela.
Un constructeur de type est un type que vous pouvez appliquer à des arguments de type pour «construire» un type.
Un constructeur de valeur est une valeur que vous pouvez appliquer à des arguments de valeur pour «construire» une valeur.
Les constructeurs de valeurs sont généralement appelés «fonctions» ou «méthodes». Ces "constructeurs" sont également dits "polymorphes" (car ils peuvent être utilisés pour construire des "trucs" de "forme" variable), ou des "abstractions" (puisqu'ils s'abstiennent sur ce qui varie entre différentes instanciations polymorphes).
Dans le contexte de l'abstraction / polymorphisme, le premier ordre se réfère à une «utilisation unique» de l'abstraction: vous abstenez sur un type une fois, mais ce type lui-même ne peut pas abstraire sur quoi que ce soit. Les génériques Java 5 sont de premier ordre.
L'interprétation de premier ordre des caractérisations ci-dessus des abstractions est:
Un constructeur de type est un type que vous pouvez appliquer aux arguments de type appropriés pour "construire" un type approprié.
Un constructeur de valeur est une valeur que vous pouvez appliquer à des arguments de valeur appropriés pour «construire» une valeur appropriée.
Pour souligner qu'il n'y a pas d'abstraction impliquée (je suppose que vous pourriez appeler cela "ordre zéro", mais je n'ai vu cela utilisé nulle part), comme la valeur 1
ou le type String
, nous disons généralement que quelque chose est une valeur ou un type "correct".
Une valeur appropriée est "immédiatement utilisable" dans le sens où elle n'attend pas d'arguments (elle ne les résume pas). Considérez-les comme des valeurs que vous pouvez facilement imprimer / inspecter (sérialiser une fonction, c'est tricher!).
Un type approprié est un type qui classe les valeurs (y compris les constructeurs de valeurs), les constructeurs de types ne classent aucune valeur (ils doivent d'abord être appliqués aux bons arguments de type pour produire un type approprié). Pour instancier un type, il est nécessaire (mais pas suffisant) que ce soit un type correct. (Il peut s'agir d'une classe abstraite ou d'une classe à laquelle vous n'avez pas accès.)
"Ordre supérieur" est simplement un terme générique qui signifie l'utilisation répétée de polymorphisme / abstraction. Cela signifie la même chose pour les types et les valeurs polymorphes. Concrètement, une abstraction d'ordre supérieur s'abstrait sur quelque chose qui s'abstrait sur quelque chose. Pour les types, le terme "de type supérieur" est une version spéciale de "l'ordre supérieur" plus général.
Ainsi, la version d'ordre supérieur de notre caractérisation devient:
Un constructeur de type est un type que vous pouvez appliquer aux arguments de type (types appropriés ou constructeurs de type) pour "construire" un type approprié (constructeur).
Un constructeur de valeur est une valeur que vous pouvez appliquer à des arguments de valeur (valeurs appropriées ou constructeurs de valeur) pour "construire" une valeur appropriée (constructeur).
Ainsi, "d'ordre supérieur" signifie simplement que lorsque vous dites "abstrait sur X", vous le pensez vraiment! Celui X
qui est abstrait ne perd pas ses propres "droits d'abstraction": il peut abstraire tout ce qu'il veut. (Soit dit en passant, j'utilise ici le verbe "abstrait" pour signifier: omettre quelque chose qui n'est pas essentiel pour la définition d'une valeur ou d'un type, afin qu'il puisse être modifié / fourni par l'utilisateur de l'abstraction comme argument .)
Voici quelques exemples (inspirés des questions de Lutz par e-mail) de valeurs et de types appropriés, de premier ordre et d'ordre supérieur:
proper first-order higher-order
values 10 (x: Int) => x (f: (Int => Int)) => f(10)
types (classes) String List Functor
types String ({type λ[x] = x})#λ ({type λ[F[x]] = F[String]})#λ
Où les classes utilisées ont été définies comme:
class String
class List[T]
class Functor[F[_]]
Pour éviter l'indirection en définissant des classes, vous devez en quelque sorte exprimer des fonctions de type anonyme, qui ne sont pas directement exprimables dans Scala, mais vous pouvez utiliser des types structurels sans trop de surcharge syntaxique (le #λ
style est dû à https://stackoverflow.com / utilisateurs / 160378 / retronym afaik):
Dans une future version hypothétique de Scala qui prend en charge les fonctions de type anonyme, vous pouvez raccourcir cette dernière ligne des exemples pour:
types (informally) String [x] => x [F[x]] => F[String]) // I repeat, this is not valid Scala, and might never be
(Sur une note personnelle, je regrette de n'avoir jamais parlé de "types de type supérieur", ce ne sont que des types! Quand vous avez absolument besoin de lever les ambiguïtés, je suggère de dire des choses comme "type constructeur paramètre", "type constructeur membre" , ou "type constructor alias", pour souligner que vous ne parlez pas uniquement des types appropriés.)
ps: Pour compliquer davantage les choses, "polymorphe" est ambigu d'une manière différente, car un type polymorphe signifie parfois un type universellement quantifié, tel que Forall T, T => T
, qui est un type approprié, car il classe les valeurs polymorphes (dans Scala, cette valeur peut être écrit comme le type structurel {def apply[T](x: T): T = x}
)