Voglio capire a basso livello cosa accadrebbe se la struttura dei dati non fosse persistente?
Diamo un'occhiata a un generatore di numeri pseudocasuali con un enorme spazio degli stati (come " Mersenne twister " con uno stato di 2450 byte) come una struttura di dati. Non vogliamo davvero usare alcun numero casuale più di una volta, quindi sembrano esserci poche ragioni per implementarlo come una struttura di dati persistente immutabile. Ora chiediamoci cosa potrebbe andare storto nel seguente codice:
mt_gen = CreateMersenneTwisterPRNGen(seed)
integral = MonteCarloIntegral_Bulk(mt_gen) + MonteCarloIntegral_Boundary(mt_gen)
La maggior parte dei linguaggi di programmazione non specifica l'ordine in cui MonteCarloIntegral_Bulk
eMonteCarloIntegral_Boundary
sarà valutato. Se entrambi prendono un riferimento a un mt_gen mutabile come argomento, il risultato di questo calcolo può dipendere dalla piattaforma. Peggio ancora, potrebbero esserci piattaforme in cui il risultato non è affatto riproducibile tra diverse esecuzioni.
Si può progettare un'efficiente struttura di dati mutabili per mt_gen in modo tale che qualsiasi interleaving dell'esecuzione di MonteCarloIntegral_Bulk
eMonteCarloIntegral_Boundary
fornisca un risultato "corretto", ma un diverso interleaving porterà in generale a un diverso risultato "corretto". Questa non riproducibilità rende la funzione corrispondente "impura" e comporta anche altri problemi.
La non riproducibilità può essere evitata applicando un ordine di esecuzione sequenziale fisso. Ma in quel caso il codice potrebbe essere organizzato in modo tale che sia disponibile un solo riferimento a mt_gen in qualsiasi momento. In un linguaggio di programmazione funzionale tipizzato, i tipi di unicità potrebbero essere utilizzati per applicare questo vincolo, consentendo in tal modo aggiornamenti sicuri mutabili anche nel contesto di linguaggi di programmazione funzionale pura. Tutto ciò può sembrare bello e dandy, ma almeno in teoria lo sono le simulazioni Monte Carlo imbarazzanti parallelamentee la nostra "soluzione" ha appena distrutto questa proprietà. Questo non è solo un problema teorico, ma un problema pratico molto reale. Tuttavia, dobbiamo modificare (la funzionalità offerta da) il nostro generatore di numeri pseudocasuali e la sequenza di numeri casuali che produce, e nessun linguaggio di programmazione può farlo automaticamente per noi. (Ovviamente possiamo usare una diversa libreria di numeri pseudocasuali che offre già la funzionalità richiesta.)
A un livello basso, le strutture di dati mutabili portano facilmente alla non riproducibilità (e quindi all'impurità), se l'ordine di esecuzione non è sequenziale e fisso. Una tipica strategia imperativa per affrontare questi problemi è di avere fasi sequenziali con ordine di esecuzione fisso, durante il quale le strutture di dati mutabili vengono modificate e fasi parallele con ordine di esecuzione arbitrario, durante le quali tutte le strutture di dati mutabili condivise rimangono costanti.
Andrej Bauer ha sollevato il problema dell'aliasing per le strutture di dati mutabili. È interessante notare che diversi linguaggi imperativi come Fortran e C hanno ipotesi diverse sull'aliasing consentito degli argomenti di funzione e la maggior parte dei programmatori non è del tutto consapevole del fatto che il loro linguaggio abbia un modello di aliasing.
L'immutabilità e la semantica del valore potrebbero essere leggermente sopravvalutate. La cosa più importante è che il sistema di tipi e il framework logico (come il modello di macchina astratto, il modello di aliasing, il modello di concorrenza o il modello di gestione della memoria) del tuo linguaggio di programmazione offrono supporto sufficiente per lavorare "in sicurezza" con dati "efficienti" strutture. L'introduzione di "spostare la semantica" in C ++ 11 potrebbe sembrare un gigantesco passo indietro in termini di purezza e "sicurezza" da un punto di vista teorico, ma in pratica è l'opposto. Il sistema dei tipi e la struttura logica del linguaggio sono stati estesi per rimuovere enormi parti del pericolo associato alla nuova semantica. (E anche se i bordi grezzi rimangono, ciò non significa che questo non possa essere migliorato da un "migliore"
Uday Reddy ha sollevato il problema che la matematica non ha mai funzionato con oggetti di dati mutabili e che i sistemi di tipi per i programmi funzionali sono ben sviluppati per oggetti di dati immutabili. Questo mi ha ricordato la spiegazione di Jean-Yves Girard secondo cui la matematica non viene utilizzata per lavorare con oggetti mutevoli, quando cerca di motivare la logica lineare.
Ci si potrebbe chiedere come estendere il sistema di tipi e la struttura logica dei linguaggi di programmazione funzionale per consentire di lavorare "in sicurezza" con strutture di dati non persistenti mutevoli "efficienti". Un problema qui potrebbe essere che la logica classica e le algebre booleane potrebbero non essere il miglior framework logico per lavorare con strutture di dati mutabili. Forse la logica lineare e i monoidi commutativi potrebbero essere più adatti a questo compito? Forse dovrei leggere ciò che Philip Wadler ha da dire sulla logica lineare come sistema di tipi per linguaggi di programmazione funzionale? Ma anche se la logica lineare non dovrebbe essere in grado di risolvere questo problema, ciò non significa che il sistema dei tipi e il framework logico di un linguaggio di programmazione funzionale non possano essere estesi per consentire "sicuri" ed "efficienti"