Bene, qualcosa noto come parametria ci dice che se consideriamo il sottoinsieme puro di ML (ovvero, nessuna ricorsione infinita ref
e tutta quella strana roba), non c'è modo di definire una funzione con questo tipo se non quella che restituisce il vuoto elenco.
Tutto è iniziato con l'articolo di Wadler “ Teoremi gratis! ”. Questo documento, in sostanza, ci dice due cose:
- Se consideriamo i linguaggi di programmazione che soddisfano determinate condizioni, possiamo dedurre alcuni teoremi interessanti semplicemente osservando la firma del tipo di una funzione polimorfica (questo si chiama Teorema di parametricità).
- ML (senza ricorsione infinita,
ref
e tutte quelle cose strane) soddisfa queste condizioni.
Dal teorema Parametricity sappiamo che se abbiamo una funzione f : 'a list -> 'b list
, allora per ogni 'a
, 'b
, 'c
, 'd
e per tutte le funzioni g : 'a -> 'c
, h : 'b -> 'd
abbiamo:
map h ∘ f = f ∘ map g
(Nota, f
a sinistra ha il tipo 'a list -> 'b list
e f
a destra è 'c list -> 'd list
.)
Siamo liberi di scegliere quello che g
ci piace, quindi lascia 'a = 'c
e g = id
. Da allora map id = id
(facile da dimostrare per induzione sulla definizione di map
), abbiamo:
map h ∘ f = f
Ora lascia 'b = 'd = bool
e h = not
. Supponiamo che per alcuni zs : bool list
capiti che succede f zs ≠ [] : bool list
. E 'chiaro che map not ∘ f = f
non non regge, perché
(map not ∘ f) zs ≠ f zs
Se il primo elemento dell'elenco a destra è true
, allora a sinistra il primo elemento è false
e viceversa!
Ciò significa che la nostra ipotesi è sbagliata e f zs = []
. Abbiamo finito? No.
Abbiamo ipotizzato che lo 'b
sia bool
. Abbiamo dimostrato che quando f
viene invocato con type f : 'a list -> bool list
per any 'a
, f
deve sempre restituire l'elenco vuoto. Può essere che quando chiamiamo f
come f : 'a list -> unit list
restituisce qualcosa di diverso? La nostra intuizione ci dice che questa è una sciocchezza: semplicemente non possiamo scrivere in puro ML una funzione che restituisce sempre la lista vuota quando vogliamo che ci dia un elenco di booleani e che altrimenti potrebbe restituire una lista non vuota! Ma questa non è una prova.
Quello che vogliamo dire è che f
è uniforme : se restituisce sempre una lista vuota per bool list
, allora deve restituire l'elenco vuoto per unit list
e, in generale, qualsiasi 'a list
. Questo è esattamente ciò di cui tratta il secondo punto dell'elenco puntato all'inizio della mia risposta.
Il documento ci dice che in ML f
deve prendere relativi valori relativi quelle. Non entrerò nei dettagli delle relazioni, è sufficiente dire che le liste sono correlate se e solo se hanno uguale lunghezza e i loro elementi sono correlati in coppia (cioè, [x_1, x_2, ..., x_m]
e [y_1, y_2, ..., y_n]
sono correlati se e solo se m = n
e x_1
sono correlati a y_1
ed x_2
è correlato y_2
e così via). E la parte divertente è, nel nostro caso, poiché f
è polimorfica, possiamo definire qualsiasi relazione sugli elementi delle liste!
Prendiamo qualsiasi 'a
, 'b
e guardare f : 'a list -> 'b list
. Ora guarda f : 'a list -> bool list
; abbiamo già dimostrato che in questo caso f
restituisce sempre l'elenco vuoto. Ora postuliamo che tutti gli elementi di 'a
sono correlati a se stessi (ricordate, possiamo scegliere qualsiasi relazione che vogliamo), questo implica che qualcuno zs : 'a list
è legato a se stesso. Come sappiamo, f
assume valori correlati a quelli correlati, ciò significa che f zs : 'b list
è correlato f zs : bool list
, ma il secondo elenco ha una lunghezza pari a zero e poiché il primo è correlato ad esso, è anche vuoto.
Per completezza, menzionerò che c'è una sezione sull'impatto della ricorsione generale (possibile non terminazione) nel documento originale di Wadler, e c'è anche un documento che esplora teoremi liberi in presenza di seq
.