web-dev-qa-db-fra.com

Qu'est-ce qu'un type plus gentil en Scala?

Vous pouvez trouver ce qui suit sur le Web:

  1. Type plus élevé == constructeur du type?

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

    Certains disent que c'est un type de type supérieur, parce qu'il résume les types qui seraient conformes à la définition.

    Les types plus élevés sont des types qui prennent d'autres types et construisent un nouveau type

    Celles-ci sont également appelées constructeur type. (Par exemple, dans programmation en Scala ).

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

    Dans le papier Génériques d'un type supérieur , vous pouvez lire

    ... types abstraites sur types abstraites sur types ("types à caractère supérieur") ... "

    ce qui suggère que

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

    est un type plus gentil.

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

256
Lutz

Permettez-moi de rattraper le début d'une partie de cette confusion en ajoutant une certaine ambiguïté. J'aime utiliser l'analogie avec le niveau de valeur pour expliquer cela, car les gens ont tendance à être plus familier avec elle.

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 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 "éléments" de "formes" variables) ou "abstractions" (puisqu'ils résument ce qui varie entre différentes instanciations polymorphes).

Dans le contexte de l'abstraction/polymorphisme, le premier ordre fait référence à un "usage unique" de l'abstraction: vous abstenez une fois sur un type, mais ce type lui-même ne peut pas faire abstraction de rien. Java 5 médicaments génériques sont du premier ordre.

Les interprétations de premier ordre des caractérisations ci-dessus des abstractions sont:

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 appropriée.

Pour souligner qu'il n'y a aucune abstraction impliquée (je suppose que vous pourriez appeler cela "ordre zéro", mais je ne l'ai jamais vu utilisé nulle part), telle que 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" en ce sens qu'elle n'attend pas d'arguments (elle ne fait pas abstraction de ceux-ci). Considérez-les comme des valeurs que vous pouvez facilement imprimer/inspecter (la sérialisation d’une fonction est une tricherie!).

Un type approprié est un type qui classifie les valeurs (y compris les constructeurs de valeurs), les constructeurs de types ne classant aucune valeur (ils doivent d'abord être appliqués aux arguments de type appropriés pour obtenir un type approprié). 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 accès.)

"Ordre supérieur" est simplement un terme générique qui signifie une utilisation répétée du polymorphisme/abstraction. Cela signifie la même chose pour les types et valeurs polymorphes. Concrètement, une abstraction d'ordre supérieur fait abstraction de quelque chose qui fait abstraction de quelque chose. Pour les types, le terme "supérieur" est une version à usage spécifique du terme 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 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 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 "résumer sur X", vous le pensez vraiment! Le X sur lequel on fait abstraction ne perd pas ses propres "droits d'abstraction": il peut résumer tout ce qu'il veut. (Au fait, j'utilise le verbe "abstrait" pour signifier: laisser de côté un élément qui n'est pas essentiel à la définition d'une valeur ou d'un type, afin qu'il puisse être modifié/fourni par l'utilisateur de l'abstraction en tant qu'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)    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 par la définition de classes, vous devez en quelque sorte exprimer des fonctions de type anonymes, 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/users/160378/retronym afaik):

Dans une version future hypothétique de Scala qui prend en charge les fonctions de type anonyme), vous pouvez raccourcir la 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 à caractères plus élevés", ils ne sont finalement que des types! Lorsque vous devez absolument lever l'ambiguïté, je suggère de dire des choses comme "type constructeur paramètre", "type constructeur constructeur" , ou "type constructeur alias", pour souligner que vous ne parlez pas seulement des types appropriés.)

ps: Pour compliquer davantage les choses, "polymorphe" est ambigu d’une manière différente, puisqu’un type polymorphe désigne parfois un type universellement quantifié, tel que Forall T, T => T, qui est un type correct, car il classe les valeurs polymorphes (dans Scala, cette valeur peut être écrite sous le type de structure {def apply[T](x: T): T = x})

260
Adriaan Moors

(Cette réponse est une tentative de décorer Adriaan Moors avec quelques informations graphiques et historiques.)

Les types plus élevés font partie de Scala depuis 2.5.

  • Avant cela, Scala, en tant que Java jusqu'à maintenant, ne permettait pas d'utiliser le constructeur de type ("génériques" en Java) à utiliser comme paramètre de type pour un constructeur de type. P. Ex.

     trait Monad [M[_]]
    

    n'était pas possible.

    Dans Scala 2.5, le système de types avait été étendu par la possibilité de classer les types à un niveau supérieur (appelé polymorphisme du constructeur de type). Ces classifications sont appelées sortes.

    Type and kind realtion, **derived** from "Generics of a Higher Kind" (Image dérivée de Génériques d'un type supérieur )

    La conséquence est que le constructeur de type (par exemple, List) pourrait être utilisé comme d’autres types dans la position de paramètre de type des constructeurs de type; 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 prenant en charge les types supérieurs, nous pouvons distinguer les types appropriés , des types tels que Int ou List[Int] des types de premier ordre comme List et des types d'un type plus élevé comme Functor ou Monad (types abstraits sur types abstraits sur types).

    Le système de types de Java de l’autre côté ne prend pas en charge les types et n’a donc aucun type de type "supérieur").

    Cela doit donc être vu dans le contexte du système de types supporté.

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

     trait Iterable[A, Container[_]]
    

    avec le titre "Types plus élevés", par ex. in Scala pour les programmeurs génériques, section 4.

    Cela est parfois trompeur, car beaucoup se réfèrent à Container comme type de type plus élevé et non Iterable, mais ce qui est plus précis est:

    l'utilisation de Container comme paramètre de constructeur de type d'un type de type supérieur (d'ordre supérieur) ici Iterable.

96
Lutz

Le type des types ordinaires tels que Int et Char, dont les instances sont des valeurs, est *. Le type de constructeur de type unaire comme Maybe est * -> *; Les constructeurs de type binaire comme Either ont ( currys ) le genre * -> * -> *, etc. Vous pouvez afficher des types tels que Maybe et Either en tant que fonctions de niveau 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 de nidification, à gauche, des flèches de fonction:

  • Ordre 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

Ainsi, en résumé, un type de type supérieur est simplement une fonction d'ordre supérieur au niveau du type.

  • Ordre 0: Int :: *
  • Ordre 1: Maybe :: * -> *
  • Ordre 2: Functor :: (* -> *) -> Constraint— de type supérieur: convertit les constructeurs de type unaire en contraintes de classe
71
Jon Purdy

Je dirais: Un type de type supérieur résume sur un constructeur de type. Par exemple. considérer

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

Ici Functor est un "type plus élevé" (tel qu'utilisé dans le "Génériques d'un type plus élevé" ). Ce n'est pas un constructeur de type concret ("premier ordre") comme List (qui résume uniquement les types appropriés). Il résume tous les constructeurs de type unaires ("du premier ordre") (notés F[_]).

Ou pour le dire autrement: en Java, nous avons clairement des constructeurs de type (par exemple, List<T>), mais nous n’avons aucun "type de type plus élevé", car nous ne pouvons pas les résumer (par exemple, nous ne pouvons pas écrire l’interface Functor 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".

31
Landei