Qu’est-ce qu’un type supérieur dans Scala?

Vous pouvez trouver ce qui suit sur le web:

  1. Type supérieur type == constructeur de type?

    class AClass[T]{...} // For example, class List[T] 

    Certains disent que c’est un type plus sympathique, car il fait abstraction des types qui seraient conformes à la définition.

    Les types associés supérieurs sont des types qui prennent d’autres types et construisent un nouveau type

    Ceux-ci sont cependant connus sous le nom de constructeur de type . (Par exemple, dans Programmation en Scala ).

  2. Constructeur de type type supérieur == qui prend le constructeur de type comme paramètre de type?

    Dans l’étude Les génériques d’un genre supérieur , vous pouvez lire

    … des types abstraits sur des types abstraits par type (“types supérieurs”) … ”

    ce qui suggère que

     class XClass[M[T]]{...} // or trait YTrait[N[_]]{...} // eg trait Functor[F[_]] 

    est un type supérieur.

Dans cette optique, il est difficile de faire la distinction entre le type constructeur , le type supérieur et le constructeur de type qui prend les constructeurs de types comme paramètre de type , donc la question ci-dessus.

Permettez-moi de compenser une partie de cette confusion en évoquant une certaine ambiguïté. J’aime utiliser l’analogie avec le niveau de valeur pour expliquer cela, car les gens ont tendance à mieux le connaître.

Un constructeur de type est un type que vous pouvez appliquer pour taper des arguments 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 “trucs” de “forme” variable, ou “abstractions” (puisqu’ils s’abstiennent sur ce qui varie entre différentes instanciations polymorphes).

Dans le contexte de l’abstraction / polymorphism, le premier ordre se réfère à «l’usage unique» de l’abstraction: vous abstractionnez sur un type une fois, mais ce type lui-même ne peut en aucun cas être abstrait. Java 5 génériques sont de premier ordre.

L’interprétation de premier ordre des caractérisations ci-dessus des abstractions est la suivante:

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 aux arguments de valeur appropriés pour “construire” une valeur correcte.

Pour souligner qu’il n’y a pas d’abstraction impliquée (je suppose que vous pourriez appeler cet “ordre zéro”, mais je n’ai jamais vu cela utilisé), comme la valeur 1 ou le type Ssortingng , nous disons généralement que quelque chose est une valeur “propre” ou type.

Une valeur propre est “immédiatement utilisable” dans le sens où elle n’attend pas les arguments (elle n’est pas abstraite). Considérez-les comme des valeurs que vous pouvez facilement imprimer / inspecter (la sérialisation d’une fonction est une sortingche!).

Un type propre 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 arguments de type correct pour obtenir un type correct). Pour instancier un type, il est nécessaire (mais pas suffisant) que ce soit un type approprié. (Il peut s’agir d’une classe abstraite ou d’une classe à laquelle vous n’avez pas access.)

“Ordre supérieur” est simplement un terme générique qui signifie l’utilisation répétée du polymorphism / de l’abstraction. Cela signifie la même chose pour les types et les valeurs polymorphes. Concrètement, une abstraction d’ordre supérieur résume quelque chose qui résume quelque chose. Pour les types, le terme “supérieur” est une version spéciale du plus général “d’ordre supérieur”.

Ainsi, la version d’ordre supérieur de notre caractérisation devient:

Un constructeur de type est un type que vous pouvez appliquer pour taper des arguments (types propres ou constructeurs de type) pour “construire” un type correct (constructeur).

Un constructeur de valeur est une valeur que vous pouvez appliquer aux arguments de valeur (valeurs correctes ou constructeurs de valeur) pour “construire” une valeur correcte (constructeur).

Ainsi, “ordre supérieur” signifie simplement que lorsque vous dites “parsingr par-dessus X”, vous le pensez vraiment! Le X qui est abstrait ne perd pas ses propres “droits d’abstraction”: il peut en résumer tout ce qu’il veut. (Soit dit en passant, j’utilise le verbe “abstract” ici 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’argument .)

Voici quelques exemples (inspirés des questions de Lutz par courrier électronique) 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) Ssortingng List Functor types Ssortingng ({type λ[x] = x})#λ ({type λ[F[x]] = F[Ssortingng]})#λ 

Où les classes utilisées ont été définies comme:

 class Ssortingng class List[T] class Functor[F[_]] 

Pour éviter l’indirection via la définition des classes, vous devez exprimer les fonctions de type anonyme, qui ne peuvent pas être exprimées directement dans Scala, mais vous pouvez utiliser des types structurels sans trop de surcharge syntaxique (le style est dû à https: // stackoverflow .com / users / 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 à:

 types (informally) Ssortingng [x] => x [F[x]] => F[Ssortingng]) // I repeat, this is not valid Scala, and might never be 

(Sur une note personnelle, je regrette d’avoir jamais parlé de “types supérieurs”, ce ne sont que des types après tout! Lorsque vous devez absolument désambiguïser, je suggère de dire des choses comme “paramètre constructeur de type”, “membre de constructeur de type” , ou “constructeur de type alias”, pour souligner que vous ne parlez pas uniquement des types appropriés.)

ps: Pour compliquer les choses, “polymorphique” 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 propre, car il classe les valeurs polymorphes ( dans Scala, cette valeur peut être écrite comme type de structure {def apply[T](x: T): T = x} )

(Cette réponse est une tentative de décorer la réponse d’Adriaan Moors par des informations graphiques et historiques.)

Les types les plus proches font partie de Scala depuis 2.5.

  • Avant cela, Scala, comme Java jusqu’à présent, ne permettait pas d’utiliser le constructeur de type (“génériques” en Java) comme paramètre de type pour un constructeur de type. par exemple

      trait Monad [M[_]] 

    n’était pas possible.

    Dans Scala 2.5, le système de types a été étendu par la possibilité de classer les types à un niveau supérieur (appelé polymorphism de constructeur de type ). Ces classifications sont connues sous le nom de types.

    Type et type de realtion, ** dérivé ** de (Image dérivée de génériques d’un genre supérieur )

    La conséquence est que ce constructeur de type (par exemple, List ) pourrait être utilisé comme les autres types dans la position du paramètre type des constructeurs de type et ils sont donc 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, on peut distinguer les types propres , les types Int ou List[Int] des types de premier ordre tels que List et les types plus Functor comme Functor ou Monad (types abstraits sur les types abstraits) sur les types).

    De l’autre côté, le système de type Java ne prend pas en charge les types et n’a donc pas de type de “type supérieur”.

    Donc, cela doit être vu dans le contexte du système de type de support.

  • Dans le cas de Scala, vous voyez souvent des exemples d’un constructeur de type comme

      trait Iterable[A, Container[_]] 

    avec le titre “Types similaires”, par exemple dans Scala pour les programmeurs génériques, section 4.3

    Cela est parfois trompeur, car beaucoup se réfèrent à Container tant que type supérieur et non Iterable , mais ce qui est plus précis, c’est que

    l’utilisation de Container tant que paramètre de constructeur de type d’un type supérieur (d’ordre supérieur) Iterable .

Le type des types ordinaires comme Int et Char , dont les instances sont des valeurs, est * . Le type de constructeur de type unaire comme Maybe est * -> * ; Les constructeurs de type binary comme Either ont ( curried ) kind * -> * -> * , etc. Vous pouvez afficher des types tels que Maybe et Either 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 (officieusement) la profondeur d’imbrication, à gauche, des flèches de fonction:

  • Commande 0: 1 :: Int
  • Ordre 1: chr :: Int -> Char
  • Ordre 2: fix :: (a -> a) -> a , map :: (a -> b) -> [a] -> [b]
  • Ordre 3: ((A -> B) -> C) -> D
  • Ordre 4: (((A -> B) -> C) -> D) -> E

Donc, à court terme, un type plus élevé n’est qu’une fonction d’ordre supérieur.

  • Commande 0: Int :: *
  • Ordre 1: Maybe :: * -> *Maybe :: * -> *
  • Ordre 2: Functor :: (* -> *) -> Constraint – plus élevé: convertit les constructeurs de type unaire en contraintes de classe

Je dirais: Un type plus élevé abstraits sur un constructeur de type. Par exemple, considérez

 trait Functor [F[_]] { def map[A,B] (fn: A=>B)(fa: F[A]): F[B] } 

Ici Functor est un “type supérieur” (utilisé dans le papier “Generics of a Higher Kind”). Ce n’est pas un constructeur de type concret (“premier ordre”) tel que List (qui résume uniquement les types appropriés). Il fait abstraction de tous les constructeurs de type unaire (“premier ordre”) (comme indiqué par F[_] ).

Ou pour le dire autrement: en Java, nous avons clairement des constructeurs de type (ex: List ), mais nous n’avons pas de «types supérieurs», car nous ne pouvons pas les résumer (par exemple, nous ne pouvons pas écrire le Interface Functor définie ci-dessus – du moins pas directement ).

Le terme “polymorphism d’ordre supérieur (constructeur de type)” est utilisé pour décrire les systèmes qui prennent en charge les “types associés supérieurs”.