Simon ha sostanzialmente ragione, da un punto di vista estensivo. Sappiamo abbastanza bene quali sono le semantiche dei moderni linguaggi funzionali, e in realtà sono variazioni relativamente piccole l'una dell'altra - ognuna di esse rappresenta traduzioni leggermente diverse in un metalinguaggio monadico. Perfino un linguaggio come Scheme (un linguaggio imperativo di ordine superiore tipizzato in modo dinamico con controllo di prima classe) ha una semantica che è abbastanza vicina a quella di ML e di Haskell.
Da un punto di vista denotazionale, si può iniziare dando un'equazione di dominio piuttosto semplice per la semantica di Scheme - lo chiamano . Alla fine degli anni '70 / primi anni '80, le persone potevano risolvere e risolvere equazioni come queste, quindi non è poi così male. Allo stesso modo, ci sono semantiche operative relativamente semplici anche per Scheme. (Nota che quando dico "Schema", intendo un calcolo lambda non tipizzato più continuazioni più stato, al contrario di Schema reale che ha alcune verruche come fanno tutte le lingue reali.)V
Ma per arrivare a una categoria adatta all'interpretazione dei linguaggi funzionali tipizzati moderni, le cose diventano piuttosto spaventose. Fondamentalmente, si finisce per costruire una categoria ultrametrica arricchita di relazioni di equivalenza parziali su questo dominio. (Ad esempio, vedi "Semantica di realizzabilità del polimorfismo parametrico, riferimenti generali e tipi ricorsivi" di Birkedal, Stovring e Thamsborg.) Le persone che preferiscono la semantica operativa conoscono queste cose come relazioni logiche indicizzate a passi. (Ad esempio, vedi "Indipendenza della rappresentanza dipendente dallo stato" di Ahmed, Dreyer e Rossberg.) Ad ogni modo, le tecniche utilizzate sono relativamente nuove.
La ragione di questa complessità matematica è che dobbiamo essere in grado di interpretare contemporaneamente il polimorfismo parametrico e lo stato di ordine superiore. Ma una volta che hai fatto questo, sei praticamente a casa libera, poiché questa costruzione contiene tutti i bit duri. Ora puoi interpretare i tipi ML e Haskell tramite le solite traduzioni monadiche. Lo spazio funzionale rigoroso ed efficace di ML si a -> b
traduce in <a right> e lo spazio delle funzioni pigro di Haskell si traduce in <a right> , con il tipo monadico di effetti collaterali che interpretano la monade IO di Haskell e è l'interpretazione del tipo ML o del tipo Haskell e ⟨ un ⟩ → T⟨ B ⟩⟨ Un ⟩ → ⟨ b ⟩T( A )⟨ Un ⟩a
→ è l'esponenziale in quella categoria di PER.
Per quanto riguarda la teoria equazionale, poiché entrambe queste lingue possono essere descritte da traduzioni in sottoinsiemi leggermente diversi della stessa lingua, è del tutto corretto chiamarle variazioni sintattiche l'una dell'altra.
La differenza di feeling tra ML e Haskell deriva in realtà dalle proprietà intensionali delle due lingue, ovvero tempo di esecuzione e consumo di memoria. ML ha un modello di performance compositiva (vale a dire, il costo tempo / spazio di un programma può essere calcolato dal costo tempo / spazio dei suoi subterm), come farebbe un vero linguaggio call-by-name. L'attuale Haskell è implementato con una chiamata per necessità, una sorta di memoizzazione e, di conseguenza, le sue prestazioni non sono composizionali - il tempo impiegato da un'espressione legata a una variabile per valutare dipende dal fatto che sia stato usato prima o meno. Questo non è modellato nella semantica cui ho accennato in precedenza.
Se vuoi prendere le proprietà intensionali più seriamente, allora ML e Haskell iniziano a mostrare differenze più serie. Probabilmente è ancora possibile escogitare un metalinguaggio comune per loro, ma l'interpretazione dei tipi differirà in un modo molto più sistematico, correlato all'idea teorica di messa a fuoco . Un buon posto per conoscere questo è la tesi di dottorato di Noam Zeilberger.