Permettez-moi de compenser cette confusion en apportant un peu de désambiguïsation. J'aime utiliser l'analogie avec le niveau de valeur pour expliquer cela, car les gens ont tendance à être plus familiers avec cette notion.
Un constructeur de type est un type que vous pouvez appliquer aux arguments de type pour "construire" un type.
Un constructeur de valeur est une valeur que vous pouvez appliquer aux 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 "choses" de forme variable), ou "abstraits" (car ils font abstraction de ce qui varie entre les différentes instanciations polymorphes).
Dans le contexte de l'abstraction/polymorphisme, le premier ordre fait référence à l'"utilisation unique" de l'abstraction : vous faites l'abstraction d'un type une fois, mais ce type lui-même ne peut pas faire l'abstraction de quoi que ce soit. Les génériques de Java 5 sont de premier ordre.
L'interprétation au premier ordre des caractérisations des abstractions ci-dessus sont :
Un constructeur de type est un type que vous pouvez appliquer à des arguments de type approprié 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'aucune abstraction n'est impliquée (je suppose qu'on pourrait appeler cela "ordre zéro", mais je n'ai jamais vu cela utilisé nulle part), comme la valeur 1
ou le type String
En général, nous disons que quelque chose est une valeur ou un type "propre".
Une valeur propre est "immédiatement utilisable" dans le sens où elle n'attend pas d'arguments (elle ne fait pas abstraction d'eux). Considérez-les comme des valeurs que vous pouvez facilement imprimer/inspecter (sérialiser une fonction est une tricherie !).
Un type correct est un type qui classifie des valeurs (y compris les constructeurs de valeurs), les constructeurs de types ne classifient aucune valeur (ils doivent d'abord être appliqués aux bons arguments de type pour produire un type correct). Pour instancier un type, il est nécessaire (mais pas suffisant) qu'il soit un type approprié. (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 du polymorphisme/de l'abstraction. Il signifie la même chose pour les types et les valeurs polymorphes. Concrètement, une abstraction d'ordre supérieur s'abstrait de quelque chose qui s'abstrait de quelque chose. Pour les types, le terme "higher-kinded" est une version spécialisée du terme plus général "higher-order".
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 propres ou constructeurs de type) pour "construire" un type propre (constructeur).
Un constructeur de valeur est une valeur que vous pouvez appliquer aux arguments de valeur (valeurs propres ou constructeurs de valeur) pour "construire" une valeur propre (constructeur).
Ainsi, "d'ordre supérieur" signifie simplement que lorsque vous dites "abstraire sur X", vous le pensez vraiment ! Le site X
qui est abstrait ne perd pas ses propres "droits d'abstraction" : il peut abstraire tout ce qu'il veut. (Au fait, j'utilise ici le verbe "abstraire" pour signifier : laisser de côté quelque chose qui n'est pas essentiel pour la définition d'une valeur ou d'un type, afin qu'il puisse être varié/fourni par l'utilisateur de l'abstraction comme argument).
Voici quelques exemples (inspirés des questions posées par Lutz par courriel) de valeurs et de types propres, 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 suit :
class String
class List[T]
class Functor[F[_]]
Pour éviter l'indirection par la définition de classes, vous devez exprimer d'une manière ou d'une autre les fonctions de type anonymes, qui ne sont pas exprimables directement en Scala, mais vous pouvez utiliser des types structurels sans trop de surcharge syntaxique (la fonction #λ
-Le style est dû à https://stackoverflow.com/users/160378/retronym afaik) :
Dans une hypothétique version future de Scala qui prendrait en charge les fonctions de type anonyme, vous pourriez raccourcir la dernière ligne de l'exemple en :
types (informally) String [x] => x [F[x]] => F[String]) // I repeat, this is not valid Scala, and might never be
(A titre personnel, je regrette d'avoir jamais parlé de "types supérieurs", ce ne sont que des types après tout ! Quand vous avez absolument besoin de désambiguïser, je suggère de dire des choses comme "paramètre de constructeur de type", "membre de constructeur de type", ou "alias de constructeur de type", pour souligner que vous ne parlez pas seulement de types propres).
ps : Pour compliquer encore les choses, "polymorphe" est ambigu d'une autre manière, puisqu'un type polymorphe signifie parfois un type universellement quantifié, tel que Forall T, T => T
qui est un type propre, puisqu'il classifie les valeurs polymorphes (en Scala, cette valeur peut être écrite comme le type structurel {def apply[T](x: T): T = x}
)
0 votes
Ajouté le foncteur de Landei comme exemple.