Vous pouvez trouver les éléments suivants sur le Web:
Constructeur de type supérieur == type?
class AClass[T]{...} // For example, class List[T]
Certains disent qu'il s'agit d'un type de type supérieur, car il résume les types qui seraient conformes à la définition.
Les types supérieurs sont des types qui prennent d'autres types et construisent un nouveau type
Ceux-ci sont également connus sous le nom de constructeur de type . (Par exemple, dans Programmation en Scala ).
Type de type supérieur == constructeur de type qui prend le constructeur de type comme paramètre de type?
Dans l'article Génériques d'un type supérieur , vous pouvez lire
... types qui s'abstiennent sur des types qui s'abstiennent sur des types ("types de type supérieur") ... "
ce qui suggère que
class XClass[M[T]]{...} // or trait YTrait[N[_]]{...} // e.g. trait Functor[F[_]]
est un type de type supérieur.
Donc, avec cela à l'esprit, il est difficile de distinguer le constructeur de type , le type de type supérieur et le constructeur de type qui prend les constructeurs de type comme paramètre de type , donc la question ci-dessus.
Réponses:
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.
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:
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 typeString
, 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:
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:
Où les classes utilisées ont été définies comme:
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:
(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}
)la source
(Cette réponse est une tentative de décorer la réponse d'Adriaan Moors par des informations graphiques et historiques.)
Les types plus élevés font partie de Scala depuis la 2.5.
Avant cela, Scala, en tant que Java jusqu'à présent, ne permettait pas d'utiliser le constructeur de type ("génériques" en Java) pour être utilisé comme paramètre de type pour un constructeur de type. par exemple
n'était pas possible.
(Image dérivée de génériques d'un type supérieur )
La conséquence est que ce constructeur de type (par exemple
List
) pourrait être utilisé comme les autres types dans la position des paramètres de type des constructeurs de type et donc ils sont devenus des types de première classe depuis Scala 2.5. (Similaire aux fonctions qui sont des valeurs de première classe dans Scala).Dans le contexte d'un système de types supportant des types supérieurs, nous pouvons distinguer les types appropriés , les types comme
Int
ou les typesList[Int]
de premier ordre commeList
et les types de type supérieur commeFunctor
ouMonad
(types qui s'abstiennent sur les types qui s'abstiennent sur les types).Le système de types de Java, d'autre part, ne prend pas en charge les types et n'a donc aucun type de "type supérieur".
Il faut donc voir cela dans le contexte du système de type de support.
Dans le cas de Scala, vous voyez souvent des exemples de constructeur de type comme
avec le titre "Types supérieurs", par exemple dans Scala pour les programmeurs génériques, section 4.3
Ceci est missleading parfois, parce que beaucoup se réfèrent à
Container
comme type supérieur kinded et nonIterable
, mais ce qui est est plus précis,la source
Le type de types ordinaires comme
Int
etChar
, dont les instances sont des valeurs, est*
. Le genre de constructeurs de type unaire commeMaybe
est* -> *
; les constructeurs de type binaire commeEither
have ( curried ) kind* -> * -> *
, et ainsi de suite. Vous pouvez afficher les types commeMaybe
et enEither
tant que fonctions au niveau du type: ils prennent un ou plusieurs types et renvoient un type.Une fonction est d'ordre supérieur si elle a un ordre supérieur à 1, où l'ordre est (informellement) la profondeur d'imbrication, à gauche, des flèches de fonction:
1 :: Int
chr :: Int -> Char
fix :: (a -> a) -> a
,map :: (a -> b) -> [a] -> [b]
((A -> B) -> C) -> D
(((A -> B) -> C) -> D) -> E
Donc, pour faire court, un type de type supérieur n'est qu'une fonction d'ordre supérieur au niveau du type.
Int :: *
Maybe :: * -> *
Functor :: (* -> *) -> Constraint
—de type supérieur: convertit les constructeurs de type unaire en contraintes de classe de typesla source
Functor
produit un type approprié (enfin, trait, mais même idée) àFunctor[F[_]]
partir d'un constructeur de typeF
.(* => *) => (* => *)
peut-il être exprimé en Scala? Sinon, dans une autre langue?* ⇒ * ⇒ *
curry est très utile. Merci!(* ⇒ *) ⇒ (* ⇒ *)
peut également être orthographié(* ⇒ *) ⇒ * ⇒ *
. Il peut être exprimé en Scala commeFoo[F[_], T]
. C'est le genre d'un type comme (dans Haskell)newtype Twice f a = Twice (f (f a))
(par exemple,Twice Maybe Int
≅Maybe (Maybe Int)
,Twice [] Char
≅[[Char]]
) ou quelque chose de plus intéressant comme la monade libredata Free f a = Pure a | Free (f (Free f a))
.Je dirais: Un type plus kinded résumés sur un constructeur de type. Par exemple, considérez
Voici
Functor
un "type de type supérieur" (tel qu'utilisé dans le document "Génériques d'un type supérieur" ). Ce n'est pas un constructeur de type concret ("de premier ordre") commeList
(qui résume uniquement les types appropriés). Il résume tous les constructeurs de type unaire ("de premier ordre") (comme indiqué parF[_]
).Ou pour le dire autrement: En Java, nous avons clairement des constructeurs de type (par exemple
List<T>
), mais nous n'avons pas de "types de type supérieur", parce que nous ne pouvons pas les abstraire (par exemple, nous ne pouvons pas écrire l'Functor
interface définie ci-dessus - du moins pas directement ).Le terme "polymorphisme d'ordre supérieur (constructeur de type)" est utilisé pour décrire les systèmes qui prennent en charge les "types de type supérieur".
la source
List<T>
Java serait un constructeur de type unaire car il en a clairement le genre* -> *
. Ce qui manque dans la réponse de Jon, c'est que vous devez être capable d'abstraire sur le "tout" (et pas seulement sur le second*
comme en Java) afin de l'appeler un type de type supérieur.def succ(x: Int) = x+1
introduit le "constructeur de valeur" (voir mon autre réponse pour ce que je veux dire par là)succ
(personne ne se réfèrerait à cette valeur comme succ (x: Int)). Par analogie,Functor
le type (en fait de type supérieur) est-il défini dans votre réponse. Encore une fois, vous ne devriez pas vous y référer commeFunctor[F[_]]
(ce qui estF
? Ce qui est_
? Ils ne sont pas dans la portée! Malheureusement, le sucre syntaxique pour les existentiels brouille les eaux ici en faisantF[_]
court pourF[T forSome {type T}]
)Scala REPL fournit une
:kind
commande quiPar exemple,
Le
:help
fournit des définitions claires, donc je pense qu'il vaut la peine de le poster ici dans son intégralité (Scala 2.13.2)la source