Terminologie correcte dans la théorie des types: types, constructeurs de types, types / sortes et valeurs


14

En réponse à une question précédente , un petit débat a commencé sur la terminologie correcte pour certaines constructions. Comme je n'ai pas trouvé de question (autre que ceci ou cela , ce qui n'est pas tout à fait la bonne chose) pour y répondre clairement, je crée cette nouvelle question.

Les termes discutables et leurs relations sont: type, constructeur de type, paramètre de type, types ou tris et valeurs .

J'ai également vérifié sur wikipedia la théorie des types, mais cela n'a pas beaucoup clarifié non plus.

Donc, pour avoir une bonne réponse de référence et pour vérifier ma propre compréhension:

  • Comment ces choses sont-elles définies correctement?
  • Quelle est la différence entre chacune de ces choses?
  • Comment sont-ils liés les uns aux autres?

Réponses:


13

D'accord, allons un par un.

Valeurs

Les valeurs sont les données concrètes que les programmes évaluent et jonglent. Rien d'extraordinaire, certains exemples pourraient être

  • 1
  • true
  • "fizz buzz foo bar"

Les types

Une belle description pour un type est "un classifieur pour une valeur". Un type est un peu d'informations sur ce que sera cette valeur au moment de l'exécution, mais indiqué au moment de la compilation.

Par exemple , si vous me dites que e : boolau moment de la compilation, et je saurai que eest soit trueou falselors de l' exécution, rien d' autre! Parce que les types classent les valeurs comme ceci, nous pouvons utiliser ces informations pour déterminer certaines propriétés de base de votre programme.

Par exemple, si jamais je vous vois ajouter eet e'quand e : intet e' : String, alors je sais que quelque chose ne va pas! En fait, je peux signaler cela et lancer une erreur au moment de la compilation, en disant "Hé, ça n'a aucun sens!".

Un système de types plus puissant permet des types plus intéressants qui classent des valeurs plus intéressantes. Par exemple, considérons une fonction

f = fun x -> x

C'est assez clair f : Something -> Something, mais qu'est-ce que cela devrait Somethingêtre? Dans un système de type ennuyeux, il faudrait spécifier quelque chose d'arbitraire, comme Something = int. Dans un système de type plus flexible, on pourrait dire

f : forall a. a -> a

C'est-à-dire "pour tout a, fmappe un aà un a". Cela nous permet d'utiliser fplus généralement et d'écrire des programmes plus intéressants.

De plus, le compilateur va vérifier réellement la satisfaction du classifieur que nous lui avons donné, si f = fun x -> truealors nous avons un bug et le compilateur le dira!

Donc, en tant que tldr; un type est une contrainte de temps de compilation sur les valeurs qu'une expression peut être au moment de l'exécution.

Constructeur de type

Certains types sont liés. Par exemple, une liste d'entiers est très similaire à une liste de chaînes. C'est presque comme sortpour les entiers, c'est presque comme sortpour les chaînes. Nous pouvons imaginer une sorte d'usine qui construit ces types presque identiques en généralisant leurs différences et en les construisant à la demande. C'est ce qu'est un constructeur de type. C'est un peu comme une fonction de types en types, mais un peu plus limité.

L'exemple classique est une liste générique. Un constructeur de type pour est juste la définition générique

 data List a = Cons a (List a) | Nil

Maintenant, Listc'est une fonction qui mappe un type aà une liste de valeurs de ce type! En Java-land, je pense que celles-ci sont peut-être appelées "classes génériques"

Paramètres de type

Un paramètre de type est simplement le type transmis à un constructeur de type (ou une fonction). Tout comme dans le niveau de valeur, nous dirions qu'il foo(a)a un paramètre atout comme le List afait un paramètre de type a.

Sortes

Les types sont un peu délicats. L'idée de base est que certains types sont similaires. Par exemple, nous avons tous les types primitifs en Java int, char, float... qui se comportent comme si elles ont le même « type ». Sauf, lorsque nous parlons des classificateurs pour les types eux-mêmes, nous appelons les types de classificateurs. Alors int : Prim, String : Box, List : Boxed -> Boxed.

Ce système donne de belles règles concrètes sur le type de types que nous pouvons utiliser où, tout comme la façon dont les types régissent les valeurs. Ce serait clairement un non-sens de dire

 List<List>

ou

 List<int>

En Java puisque Listdoit être appliqué à un type concret pour être utilisé comme ça! Si nous regardons leurs types List : Boxed -> Boxedet depuis Boxed -> Boxed /= Boxed, ce qui précède est une sorte d'erreur!

La plupart du temps, nous ne pensons pas vraiment aux types et les traitons simplement comme du "bon sens", mais avec des systèmes de type plus sophistiqués, il est important de penser à quelque chose.

Une petite illustration de ce que j'ai dit jusqu'à présent

 value   : type : kind  : ...
 true    : bool : Prim  : ...
 new F() : Foo  : Boxed : ...

Meilleure lecture que Wikipedia

Si vous êtes intéressé par ce genre de chose, je vous recommande fortement d'investir dans un bon manuel. La théorie des types et le PLT en général sont assez vastes et sans base de connaissances cohérente, vous (ou du moins moi) pouvez vous promener sans aller nulle part pendant des mois.

Deux de mes livres préférés sont

  • Types et langage de programmation - Ben Pierce
  • Fondements pratiques des langages de programmation - Bob Harper

Les deux sont d'excellents livres qui présentent ce dont je viens de parler et beaucoup plus dans de beaux détails bien expliqués.


1
Les types sont des ensembles? J'aime mieux "classificateur", mais vous n'expliquez pas ce que cela signifie, et sans une bonne compréhension de ce qu'est un type, le reste de votre réponse tombe en quelque sorte.
Robert Harvey

@RobertHarvey À quoi cela ressemble-t-il maintenant, j'ai abandonné toutes les mentions de sets :)
Daniel Gratzer

1
Beaucoup mieux ....
Robert Harvey

@RobertHarvey Je trouve la vue des types comme des ensembles très intuitive. Par exemple, le type inten Java consiste en un ensemble de 2 ^ 64 valeurs distinctes. L'analogie avec les ensembles se décompose lorsque les sous-types sont impliqués, mais c'est une intuition initiale suffisamment bonne, surtout si l'on considère les types de données algébriques (par exemple, une union de deux types peut contenir l'un des membres de l'un ou l'autre type; c'est l'union de ces ensembles) .
Doval

@Doval: Si j'écris une classe qui décrit un client, cela va probablement représenter un "ensemble" de clients, car je vais faire une collection d'instances. Mais dire qu'un client est un type parce qu'il décrit un «ensemble» de clients est une tautologie; cela semble évident. Ce qui est plus intéressant, c'est qu'un type de client décrit les caractéristiques d'un client. Utiliser "set" pour expliquer cela semble plus ... abstrait qu'il ne l'est en réalité. À moins que vous ne soyez peut-être mathématicien.
Robert Harvey

2

Comment ces choses sont-elles définies correctement?

Ils sont correctement définis par un support mathématique rigide et académique, fournissant des affirmations solides sur ce qu'ils sont, comment ils fonctionnent et ce qui est garanti.

Mais les programmeurs n'ont généralement pas besoin de le savoir. Ils ont besoin de comprendre les concepts.

Valeurs

Commençons par les valeurs, puisque tout se construit à partir de là. Les valeurs sont les données utilisées en informatique. Selon l'approche, ce sont les valeurs que tout le monde connaît: 42, 3.14, "How now brown cow", le dossier personnel de Jenny en comptabilité, etc.

D'autres interprétations de valeurs sont des symboles . La plupart des programmeurs comprennent que ces symboles sont les "valeurs" d'une énumération. Leftet Rightsont des symboles pour l'énum Handedness(en ignorant les personnes ambidextres et les poissons).

Quelle que soit l'implémentation, les valeurs sont les différentes choses avec lesquelles le langage travaille pour effectuer des calculs.

Les types

Le problème avec les valeurs est que tous les calculs ne sont pas légaux pour toutes les valeurs. 42 + goatn'a pas vraiment de sens.

C'est là que les types entrent en jeu. Les types sont des métadonnées qui définissent des sous-ensembles de valeurs. L' Handednessénumération ci-dessus est un bon exemple. Ce type indique "uniquement Leftet Rightpeut être utilisé ici". Cela permet aux programmes de déterminer très tôt que certaines opérations entraîneront des erreurs.

Une autre utilisation pratique à considérer est que sous le capot, les ordinateurs fonctionnent avec des octets. L'octet 42 pourrait signifier le nombre 42, ou il pourrait signifier le caractère *, ou cela pourrait signifier Jenny de la comptabilité. Les types également (en utilisation pratique, pas tellement théorique) aident à définir le codage pour la collection sous-jacente d'octets utilisée par les ordinateurs.

Sortes

Et voici où nous commençons à aller un peu là-bas. Ainsi, lorsqu'un langage de programmation a une variable qui fait référence à un type, de quel type s'agit- il ?

En Java et C # par exemple, il a le type Type(qui a le type Type, qui a ... et ainsi de suite). C'est le concept derrière les types . Dans certains langages, vous pouvez faire des choses un peu plus utiles avec une variable Type que Java et C #. Une fois que cela se produit, il devient utile de dire "Je veux une valeur qui soit un type, mais aussi une sorte de IEnumerable<int>". Ta-da! Sortes.

La plupart des programmeurs peuvent penser à des types comme les contraintes génériques Java et C #. Considérez public class Foo<T> where T: IComparable{}. Dans une langue avec des sortes, la T: kindOf(IComparable)déclaration de variable devient légale; pas seulement une chose spéciale que vous pouvez faire dans les déclarations de classe et de fonction.

Constructeurs de types

Sans surprise, les constructeurs de types sont simplement des constructeurs de types . "Mais comment construire un type? Les types le sont tout simplement .". Eh ... pas tellement.

Sans surprise, il est assez difficile de créer tous les différents sous-ensembles de valeurs utiles qu'un programme informatique utilisera jamais. Les constructeurs de types travaillent pour aider les programmeurs à "construire" ces sous-ensembles de manière significative.

L'exemple le plus omniprésent d'un constructeur de type est une définition de tableau: int[4]. Ici, vous spécifiez 4le constructeur de type, qui utilise la valeur pour vous construire un tableau de ints avec 4 entrées. Si vous spécifiez un type d'entrée différent, vous obtiendrez un type de sortie différent.

Les génériques sont une autre forme de constructeur de type, prenant un autre type comme entrée.

Dans de nombreux langages, il existe un constructeur de type comme P -> Rpour construire un type qui représente une fonction qui prend le type Pet retourne le type R.

Maintenant, le contexte déterminera si une "fonction qui retourne un type" est un constructeur de type ou non. D'après mon expérience (certes limitée), la ligne est "pouvez-vous utiliser ce type au moment de la compilation?". Oui? Constructeur de type. Non? Juste une fonction.

Paramètre de type

Vous vous souvenez donc des paramètres passés aux constructeurs de types? Ils sont communément appelés paramètres de type, car la forme courante d'un constructeur de type est Type[param]or Type<param>.


1
Pourriez-vous clarifier / étendre la section sur les «types»? Dans Haskell, un type a kind *, tandis qu'un constructeur de type (avec un argument) a kind * -> *. Les contraintes telles que (Num a) => a(signifiant "tout type aqui est une instance de la Numclasse de types") ne sont pas elles-mêmes des types. La classe de caractères Numn'est pas un «type» en soi, mais a le type * -> Constraint. Je trouve difficile de relier l'idée de Haskell d'un «genre» (qui, je suppose, est étroitement liée aux types dans la théorie des types?) Aux exemples que vous donnez.
John Bartholomew

Je devrais dire que le :kindcommandement de ghci donne le genre de Numas * -> Constraint. Cela pourrait être spécifique au GHC, je ne sais pas.
John Bartholomew

@JohnBartholomew - Les types Haskell sont davantage des "signatures pour les constructeurs de types". Malheureusement, mon Haskell n'est pas au point où je serais à l'aise de trop parler des détails.
Telastyn
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.