2010-06-19 19 views
16

Poiché le variabili di tipo non possono contenere i poly-types, sembra che con Rank * Types non riusciamo a riutilizzare le funzioni esistenti a causa della loro limitazione monotipo.I valori Rank2Types/RankNTypes sono pratici senza le variabili polytype?

Ad esempio, non è possibile utilizzare la funzione (.) Quando il tipo intermedio è un politipo. Siamo costretti a ri-implementare (.) Sul posto. Questo è ovviamente banale per (.) Ma un problema per corpi di codice più sostanziali.

Penso anche che fare ((f g) x) non equivalga a (f (g x)) un duro colpo alla trasparenza referenziale e ai suoi benefici.

Mi sembra un problema di show-stopper e sembra che le estensioni di Rank * Types siano quasi impraticabili per l'uso diffuso.

mi sto perdendo qualcosa? Esiste un piano per rendere i gradi di Rank * più interattivi con il resto del sistema di tipi?

MODIFICA: come si può rendere funzionanti i tipi di (runST per sempre)?

risposta

11

La proposta più recente per i tipi di Rank-N è la carta FPH collegata a Don. Secondo me è anche il più bello del gruppo. L'obiettivo principale di tutti questi sistemi è quello di richiedere il minor numero possibile di annotazioni di testo. Il problema è che quando si passa da Hindley/Milner a System F perdiamo tipi principali e l'inferenza di tipo diventa indecidibile - da qui la necessità di annotazioni di tipo.

L'idea di base dei "tipi di boxe" è di propagare le annotazioni di tipo il più lontano possibile. Il controllo del tipo consente di passare dalla verifica del tipo alla modalità di inferenza del tipo e, auspicabilmente, non sono necessarie ulteriori annotazioni. Il rovescio della medaglia qui è che l'annotazione del tipo è richiesta o meno è difficile da spiegare perché dipende dai dettagli di implementazione.

Il sistema MLF di Remy è finora la proposta più bella; richiede la minima quantità di annotazioni di tipo ed è stabile in molte trasformazioni di codice. Il problema è che estende il sistema di tipi. Il seguente esempio illustra questa norma:

choose :: forall a. a -> a -> a 
id :: forall b. b -> b 

choose id :: forall c. (c -> c) -> (c -> c) 
choose id :: (forall c. c -> c) -> (forall c. c -> c) 

Entrambi i tipi di cui sopra sono admissable in System F. Il primo è il tipo Hindley/Milner standard utilizza istanziazione predicativo, la seconda utilizza istanziazione impredicativa. Nessuno dei due tipi è più generale dell'altro, quindi l'inferenza di tipo dovrebbe indovinare quale tipo l'utente desidera e di solito è una cattiva idea.

MLF estende invece il sistema F con quantificazione limitata.Il principale (= più generale) tipo per l'esempio di cui sopra potrebbe essere:

choose id :: forall (a < forall b. b -> b). a -> a 

si può leggere questo come "choose id è digitare a-a dove a deve essere un'istanza di forall b. b -> b".

È interessante notare che questo da solo non è più potente del normale Hindley/Milner. Pertanto MLF consente anche la quantificazione rigida. I due tipi seguenti sono equivalenti:

(forall b. b -> b) -> (forall b. b -> b) 
forall (a = forall b. b -> b). a -> a 

quantificazione rigide è introdotta da annotazioni di tipo ei dettagli tecnici sono infatti piuttosto complicato. Il vantaggio è che MLF ha bisogno solo di poche annotazioni di tipo e c'è una semplice regola per quando è necessario. I lati negativi sono:

  • tipi possono diventare difficili da leggere, perché il lato destro della '<' può contenere quantificazioni ulteriormente nidificate.

  • Fino a poco tempo fa non esisteva una variante esplicita di MLF. Questo è importante per le trasformazioni del compilatore digitato (come fa GHC). La parte 3 di Boris Yakobowski's PhD thesis ha un primo tentativo con una tale variante. (Parti 1 & 2 sono interessanti, descrivono una rappresentazione più intuitiva FML tramite "Tipi grafici".)

Tornando FPH, la sua idea di base è quella di utilizzare tecniche MLF internamente, ma richiedono tipo annotazioni su attacchi let. Se si desidera solo il tipo Hindley/Milner, non sono necessarie annotazioni. Se si desidera un tipo di rango più elevato, è necessario specificare il tipo richiesto, ma solo al bind di let (o di livello superiore).

FPH (come MLF) supporta l'istanziazione impredicativa, quindi non penso che il problema si applichi. Non dovrebbe quindi esserci alcun problema a digitare la tua espressione f . g sopra. Tuttavia, FPH non è ancora stato implementato in GHC e molto probabilmente non lo sarà. Le difficoltà derivano dall'interazione con le coercizioni di uguaglianza (e possibilmente scrivono vincoli di classe). Non sono sicuro di quale sia l'ultimo stato, ma ho sentito che SPJ vuole allontanarsi dall'impredicatività. Tutto quel potere espressivo ha un costo, e finora non è stata trovata alcuna soluzione economica e onnicomprensiva.

7

Esiste un piano per rendere i tipi di Rank * più interattivi con il resto del sistema di tipi?

Dato quanto comune è il monade ST, almeno i tipi di grado 2 sono abbastanza comuni da dimostrare il contrario. Tuttavia, si potrebbe guardare la serie di articoli "sexy/boxy types", per come gli approcci per rendere il polimorfismo di grado arbitrario suonino meglio con gli altri.

FPH : First-class Polymorphism for Haskell, Dimitrios Vytiniotis, Stephanie Weirich, e Simon Peyton Jones, ha presentato al ICFP 2008.

Vedi anche -XImpredicativeTypes - che è interessante, è previsto per deprecazione!

+0

Come si può rendere funzionanti i tipi di (runST per sempre)? – Peaker

6

Informazioni su ImpredicativeTypes: che in realtà non fa differenza (sono relativamente sicuro) alla domanda di peaker. Questa estensione ha a che fare con i tipi di dati. Ad esempio, GHC ti dirà che:

Maybe :: * -> * 
(forall a. a -> a) :: * 

Tuttavia, questo è una sorta di bugia. È vero in un sistema impredicativo, e in un tale sistema, è possibile scrivere:

Maybe (forall a. a -> a) :: * 

e funzionerà correttamente. Questo è ciò che consente ImpredicativeTypes. Senza l'estensione, il modo appropriato di pensare a questo è:

Maybe :: *m -> *m 
(forall a :: *m. a -> a) :: *p 

e quindi c'è una sorta mancata corrispondenza quando si tenta di formare l'applicazione sopra.

GHC è piuttosto incoerente sul fronte dell'impredicatività, però.Per esempio, il tipo per id ho dato sopra sarebbe:

id :: (forall a :: *m. a -> a) 

ma GHC accetterà felice l'annotazione (con RankNTypes abilitati, ma non ImpredicativeTypes):

id :: (forall a. a -> a) -> (forall a. a -> a) 

anche se forall a. a -> a non è un monotipo. Quindi, consentirà l'istanziazione impredicativa di variabili quantificate che vengono utilizzate solo con (->) se si annota come tale. Ma non lo farà da solo, immagino, che porta ai problemi runST $ .... Una volta veniva risolto con una regola di istanziazione ad hoc (i cui dettagli non sono mai stati particolarmente chiari), ma questa regola è stata rimossa non molto tempo dopo che è stata aggiunta.

Problemi correlati