Ci ho pensato un po '. Il problema principale è che in generale non sappiamo quanto sia grande un valore di tipo polimorfico. Se non disponi di queste informazioni, devi ottenerle in qualche modo. La monomorfizzazione ottiene queste informazioni per te specializzando il polimorfismo. La boxe ottiene queste informazioni per te mettendo tutto in una rappresentazione di dimensioni conosciute.
Una terza alternativa è quella di tenere traccia di queste informazioni nei tipi. Fondamentalmente, ciò che puoi fare è introdurre un tipo diverso per ogni dimensione dei dati, e quindi le funzioni polimorfiche possono essere definite su tutti i tipi di una determinata dimensione. Schizzo un tale sistema qui sotto.
tipiDigitare costruttoriκUN: : = N: : =|∀ a : κ .UN|α|A × B|A + B|A → Br e fUN|P a d ( k )|μ α : κ .UN
Qui, l'idea di alto livello è che il tipo di un tipo ti dice quante parole ci vogliono per disporre un oggetto in memoria. Per ogni data dimensione, è facile essere polimorfico su tutti i tipi di quella particolare dimensione. Poiché ogni tipo, anche quelli polimorfici, ha ancora una dimensione nota, la compilazione non è più difficile di quanto lo sia per C.
Le regole di kinding trasformano questo inglese in matematica e dovrebbero assomigliare a questo:
α : n ∈ ΓΓ ⊢ α :nΓ , α : n ⊢ A : mΓ ⊢ ∀ α : n .A : m
Γ ⊢ A : nΓ ⊢ B : mΓ ⊢ A × B : n + mΓ ⊢ A : nΓ ⊢ B : nΓ ⊢ A + B : n + 1
Γ ⊢ A : mΓ ⊢ B : nΓ ⊢ A → B : 1Γ ⊢ A : nΓ ⊢ r e fA : 1
A ⊢ P a d ( k ) : kΓ , α : n ⊢ A : nΓ ⊢ μ α : n .A : n
Quindi il quantificatore forall richiede che tu dia il tipo che stai superando. Allo stesso modo, l'associazione è un tipo di coppia non in box, che indica semplicemente una accanto a una in memoria (come un tipo di struttura C). I sindacati disgiunti assumono due valori della stessa dimensione, quindi aggiungono una parola per un tag discriminatore. Le funzioni sono chiusure, rappresentate come al solito da un puntatore a un record dell'ambiente e del codice.A × BUNB
I riferimenti sono interessanti: i puntatori sono sempre una parola, ma possono indicare valori di qualsiasi dimensione. Ciò consente ai programmatori di implementare il
polimorfismo su oggetti arbitrari mediante la boxe, ma non richiede
loro di farlo. Infine, una volta che sono in gioco dimensioni esplicite, è spesso utile introdurre un tipo di imbottitura, che utilizza lo spazio ma non fa nulla. (Quindi se vuoi prendere l'unione disgiunta di un int e una coppia di ints, dovrai aggiungere il primo int di riempimento, in modo che il layout dell'oggetto sia uniforme.)
I tipi ricorsivi hanno la regola di formazione standard, ma si noti che le occorrenze ricorsive devono avere le stesse dimensioni, il che significa che di solito è necessario inserirle in un puntatore per far funzionare la digitazione. Ad esempio, il tipo di dati elenco potrebbe essere rappresentato come
μ α : 1.r e f( P a d ( 2 ) + i n t × α )
Quindi questo punta a un valore di elenco vuoto o a una coppia di un int e un puntatore a un altro elenco collegato.
Anche la verifica del tipo per sistemi come questo non è molto difficile; l'algoritmo nel mio articolo ICFP con Joshua Dunfield, il controllo dei caratteri bidirezionale completo e facile per il polimorfismo di rango superiore si applica a questo caso quasi senza modifiche.