Terminologia corretta nella teoria dei tipi: tipi, costruttori di tipi, tipi / specie e valori


14

In una risposta a una domanda precedente , è iniziato un piccolo dibattito sulla terminologia corretta per alcuni costrutti. Dato che non ho trovato una domanda (diversa da questa o quella , che non è proprio la cosa giusta) per rispondere in modo chiaro, sto realizzando questa nuova.

I termini discutibili e le loro relazioni sono: tipo, tipo costruttore, tipo parametro, tipi o ordinamenti e valori .

Ho anche controllato Wikipedia per la teoria dei tipi, ma neanche questo mi ha chiarito molto.

Quindi, per avere una buona risposta di riferimento e per verificare la mia comprensione:

  • Come vengono definite correttamente queste cose?
  • Qual è la differenza tra ciascuna di queste cose?
  • In che modo sono collegati tra loro?

Risposte:


13

Bene, andiamo uno per uno.

Valori

I valori sono i dati concreti che i programmi valutano e manipolano. Niente di speciale, alcuni esempi potrebbero essere

  • 1
  • true
  • "fizz buzz foo bar"

tipi

Una bella descrizione per un tipo è "un classificatore per un valore". Un tipo è un po 'di informazioni su quale sarà quel valore in fase di esecuzione, ma indicato al momento della compilazione.

Ad esempio, se me lo dici e : boolal momento della compilazione, e saprò che eè trueo falsedurante il runtime, nient'altro! Poiché i tipi classificano i valori in questo modo, possiamo usare queste informazioni per determinare alcune proprietà di base del tuo programma.

Ad esempio, se mai ti vedessi aggiungere e e e'quando e : inte e' : String, allora so che qualcosa è un po 'fuori! In effetti posso segnalarlo e lanciare un errore in fase di compilazione, dicendo "Ehi, non ha alcun senso!".

Un sistema di tipi più potente consente tipi più interessanti che classificano valori più interessanti. Ad esempio, consideriamo alcune funzioni

f = fun x -> x

È abbastanza chiaro f : Something -> Something, ma quale dovrebbe Somethingessere? In un sistema di tipo noioso, dovremmo specificare qualcosa di arbitrario, comeSomething = int . In un sistema di tipo più flessibile, potremmo dire

f : forall a. a -> a

Vale a dire "per qualsiasi a, fmappe una a un a". Questo usiamo fpiù in generale e scriviamo programmi più interessanti.

Inoltre, il compilatore verificherà effettivamente la soddisfazione del classificatore che gli abbiamo dato, se f = fun x -> truepoi abbiamo un bug e il compilatore lo dirà!

Quindi come un tldr; un tipo è un vincolo di tempo di compilazione sui valori che un'espressione può essere in fase di esecuzione.

Costruttore di tipo

Alcuni tipi sono correlati. Ad esempio, un elenco di numeri interi è molto simile a un elenco di stringhe. Questo è quasi come sortper i numeri interi è quasi comesort per le stringhe. Possiamo immaginare una sorta di fabbrica che costruisce questi tipi quasi uguali generalizzando le loro differenze e costruendole su richiesta. Ecco cos'è un costruttore di tipi. È un po 'come una funzione da tipi a tipi, ma un po' più limitata.

L'esempio classico è un elenco generico. Un costruttore di tipi per è solo la definizione generica

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

Ora Listè una funzione che associa un tipo aa un elenco di valori di quel tipo! In Java-land penso che queste siano forse chiamate "classi generiche"

Tipo di parametri

Un parametro di tipo è solo il tipo passato a un costruttore di tipo (o funzione). Proprio come nel livello di valore, diremmo che foo(a)ha un parametro, aproprio come List aha un parametro di tipo a.

tipi

I tipi sono un po 'complicati. L'idea di base è che alcuni tipi sono simili. Per esempio, abbiamo tutti i tipi primitivi in Java int, char, float... che tutti si comportano come se avessero lo stesso "tipo". Tranne, quando parliamo dei classificatori per i tipi stessi, chiamiamo i tipi di classificatori. Quindi int : Prim, String : Box, List : Boxed -> Boxed.

Questo sistema fornisce delle buone regole concrete su quale tipo di tipi possiamo usare dove, proprio come i tipi governano i valori. Sarebbe chiaramente una sciocchezza da dire

 List<List>

o

 List<int>

In Java da allora Listdeve essere applicato a un tipo concreto per essere usato così! Se guardiamo ai loro tipi List : Boxed -> Boxede da allora Boxed -> Boxed /= Boxed, quanto sopra è un errore gentile!

Il più delle volte non pensiamo davvero ai tipi e li trattiamo semplicemente come "buon senso", ma con sistemi di tipo più elaborato è qualcosa di importante a cui pensare.

Una piccola illustrazione di ciò che ho detto finora

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

Migliore lettura di Wikipedia

Se sei interessato a questo genere di cose, ti consiglio vivamente di investire un buon libro di testo. La teoria dei tipi e il PLT in generale sono piuttosto vasti e senza una base coerente di conoscenza che tu (o almeno io) puoi vagare senza andare da nessuna parte per mesi.

Due dei miei libri preferiti sono

  • Tipi e linguaggio di programmazione - Ben Pierce
  • Fondamenti pratici dei linguaggi di programmazione - Bob Harper

Entrambi sono libri eccellenti che introducono ciò di cui ho appena parlato e molto altro in dettagli meravigliosi e ben spiegati.


1
I tipi sono insiemi? Mi piace meglio il "classificatore", ma non spieghi cosa significhi, e senza una buona comprensione di cosa sia un tipo, il resto della tua risposta cade.
Robert Harvey,

@RobertHarvey Come sembra adesso, ho lasciato cadere tutte le menzioni dei set :)
Daniel Gratzer,

1
Molto meglio ....
Robert Harvey,

@RobertHarvey Trovo la visualizzazione dei tipi come set molto intuitiva. Ad esempio, il tipo intin Java è costituito da un insieme di 2 ^ 64 valori distinti. L'analogia con gli insiemi si interrompe quando vengono coinvolti i sottotipi, ma è un'intuizione iniziale abbastanza buona, specialmente quando si considerano i tipi di dati algebrici (ad es. Un'unione di due tipi può contenere uno qualsiasi dei membri di entrambi i tipi; è l'unione di quegli insiemi) .
Doval,

@Doval: se scrivo una classe che descrive un cliente, probabilmente rappresenterà un "insieme" di clienti, dal momento che farò una raccolta di istanze. Ma dire che un cliente è un tipo perché descrive un "insieme" di clienti è una tautologia; sembra ovvio. Ciò che è più interessante è che un tipo di Cliente descrive le caratteristiche di un cliente. Usare "set" per spiegare questo sembra più ... astratto di quanto non sia in realtà. A meno che, forse, tu non sia un matematico.
Robert Harvey,

2

Come vengono definite correttamente queste cose?

Sono adeguatamente definiti da un rigido supporto matematico accademico, che fornisce forti affermazioni su ciò che sono, come funzionano e ciò che è garantito.

Ma i programmatori in gran parte non hanno bisogno di saperlo. Devono capire i concetti.

Valori

Cominciamo con i valori, poiché tutto si basa da lì. I valori sono i dati utilizzati nell'informatica. A seconda dell'approccio, sono i valori che tutti conoscono: 42, 3.14, "How now brown cow", il personale registrato per Jenny in Accounting, ecc.

Altre interpretazioni di valori sono simboli . La maggior parte dei programmatori capisce che questi simboli sono i "valori" di un elenco. LefteRight sono simboli per l'enum Handedness(ignorando le persone e i pesci ambidestri).

Indipendentemente dall'implementazione, i valori sono le diverse cose con cui la lingua lavora per eseguire i calcoli.

tipi

Il problema con i valori è che non tutti i calcoli sono legali per tutti i valori. 42 + goatnon ha davvero senso.

È qui che entrano in gioco i tipi. I tipi sono metadati che definiscono sottoinsiemi di valori. L' Handednessenum sopra è un buon esempio. Questo tipo dice "solo Lefte Rightpuò essere usato qui". Ciò consente ai programmi di determinare molto presto che determinate operazioni comporteranno errori.

Un altro uso pratico da considerare è che sotto il cofano, i computer funzionano con i byte. Il byte 42 potrebbe significare il numero 42, oppure potrebbe significare il carattere *, oppure potrebbe significare Jenny da Contabilità. Anche i tipi (nell'uso pratico, non tanto teorico) aiutano a definire la codifica per la raccolta di byte sottostante utilizzata dai computer.

tipi

Ed ecco dove iniziamo ad andare un po 'là fuori. Così, quando un linguaggio di programmazione ha una variabile che fa riferimento a un tipo, che tipo non lo ha?

In Java e C # per esempio, ha il tipo Type(che ha il tipo Type, che ha ... e così via fino in fondo). Questo è il concetto alla base dei generi . In alcune lingue, puoi fare cose un po 'più utili con una variabile Type rispetto a Java e C #. Una volta che ciò accade, diventa utile dire "Voglio un valore che sia un Tipo, ma è anche una specie di IEnumerable<int>". Ta-da! I tipi.

La maggior parte dei programmatori può pensare a tipi come vincoli generici Java e C #. Prendere in considerazione public class Foo<T> where T: IComparable{}. In una lingua con tipi, la T: kindOf(IComparable)dichiarazione variabile diventa legale; non solo una cosa speciale che puoi fare nelle dichiarazioni di classe e funzione.

Costruttori di tipo

Forse non sorprende che i costruttori di tipi siano semplicemente costruttori di tipi . "Ma come si costruisce un tipo? I tipi sono semplicemente ". Eh ... non così tanto.

Inoltre, non sorprende che sia abbastanza difficile costruire tutti i diversi utili sottoinsiemi di valori che qualsiasi programma per computer utilizzerà mai. I costruttori di tipi lavorano per aiutare i programmatori a "costruire" questi sottoinsiemi in modi significativi.

L'esempio più diffuso di un costruttore di tipo è una definizione di matrice: int[4]. Qui stai specificando 4il tipo costruttore, che usa il valore per costruirti una matrice di ints con 4 voci. Se hai specificato un tipo di input diverso, otterrai un tipo di output diverso.

I generici sono un'altra forma di costruttore di tipi, prendendo un altro tipo come input.

In molte lingue esiste un costruttore di tipi come P -> Rcostruire un tipo che rappresenta una funzione che accetta il tipo Pe restituisce il tipo R.

Ora, il contesto determinerà se una "funzione che restituisce un tipo" è un costruttore di tipi o meno. Nella mia (certamente limitata) esperienza, la riga è "puoi usare questo tipo in fase di compilazione?". Sì? Digita costruttore. No? Solo una funzione.

Tipo di parametro

Quindi ricordi i parametri passati a Type Constructors? Sono comunemente noti come parametri di tipo, poiché la forma comune di un costruttore di tipi è Type[param]o Type<param>.


1
Potresti chiarire / estendere la sezione su "Kinds"? In Haskell, un tipo ha tipo *, mentre un costruttore di tipo (con un argomento) ha tipo * -> *. Vincoli come (Num a) => a(che significa "qualsiasi tipo ache sia un'istanza della Numtypeclass") non sono essi stessi tipi. La typeclass Numnon è un 'tipo' in sé, ma ha il tipo * -> Constraint. Trovo difficile mettere in relazione l'idea di Haskell di un "tipo" (che presumo sia strettamente correlato ai tipi nella teoria dei tipi?) Con gli esempi che dai.
John Bartholomew,

Dovrei dire, il :kindcomando di ghci dà il tipo di Numcome * -> Constraint. Questo potrebbe essere specifico per GHC, non lo so.
John Bartholomew,

@JohnBartholomew - I tipi di Haskell sono più delle "firme per i costruttori di tipi". Sfortunatamente, il mio Haskell non è quasi al punto in cui mi sentirei a mio agio a parlare troppo dei particolari.
Telastyn,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.