2010-01-28 13 views

risposta

33

Quali alternative ci sono per monadi per I/O in un linguaggio funzionale puro?

Sono consapevole di due alternative nella letteratura:

  • Uno è un cosiddetto tipo di sistema lineari. L'idea è che un valore di tipo lineare deve essere utilizzato esattamente una volta: non puoi ignorarlo e non puoi usarlo due volte. Tenendo presente questa idea, dai uno stato del mondo a un tipo astratto (ad es., World) e lo rendi lineare. Se contrassegno i tipi lineari con una stella, ecco i tipi di alcune operazioni di I/O:

    getChar :: World* -> (Char, World*) 
    putChar :: Char -> World* -> World* 
    

    e così via. Il compilatore si assicura di non copiare mai il mondo, e quindi può organizzare la compilazione del codice che aggiorna il mondo sul posto, il che è sicuro perché c'è solo una copia.

    L'univocità di digitazione nella lingua Clean si basa sulla linearità.

    Questo sistema ha un paio di vantaggi; in particolare, non impone l'ordine totale sugli eventi che fanno le monadi. Tende anche ad evitare il "bin IO" che vedi in Haskell dove tutti i computazioni efficaci vengono gettati nella monade IO e tutti vengono ordinati totalmente se si desidera o meno l'ordine totale.

  • L'altro sistema io sappia è anteriore monadi e pulito e si basa sull'idea che un programma interattivo è una funzione da una (possibilmente infinita) sequenza di richieste ad una (possibilmente infinita) sequenza di risposte. Questo sistema, che era chiamato "dialoghi", era un programma da programmare. Nessuno lo manca e non aveva niente in particolare da consigliarlo. I suoi difetti sono enumerati bene in the paper that introduced monadic I/O (Imperative Functional Programming) da Wadler e Peyton Jones. Questo documento menziona anche un sistema di I/O basato su continuazioni che è stato introdotto dal gruppo Yale Haskell ma che è stato di breve durata.

+1

Il sequenziamento tramite l'associazione monad è praticamente solo lo stile di passaggio continuo seguito dal tipo, non è vero? La mia impressione è che le monadi e le continuazioni siano per lo più intercambiabili, eccetto che le continuazioni non sono decisamente, in generale, calde * o * sfocate. –

+2

Le continuazioni formano una monade ma le monadi sono decisamente * non * continuazioni. CPS è molto più potente perché ti è permesso fare copie di cose (incluse le continuazioni!). Le Monade limitano le cose molto più severamente del semplice controllo dei caratteri. –

+0

"Le Monade sono decisamente non continuazioni" - no, ma la relazione non è solo un'Istanza. Cf. http://lambda-the-ultimate.org/node/3235 Lawvere Theories and Monads, Hyland & Power, 2007. –

4

tipizzazione unicità è utilizzato in Clean

5

Se per "puro" si intende "referenzialmente trasparente", cioè che una funzione applicata è liberamente intercambiabile con il risultato valutato (e quindi che chiamare una funzione con lo stesso gli argomenti hanno lo stesso risultato ogni volta), qualsiasi concetto di IO stateful è praticamente escluso per definizione.

Ci sono due strategie di massima che io sappia:

  • Diamo una funzione faccio IO, ma fare in modo che non può mai essere chiamato due volte con gli stessi argomenti; questo lato - risolve il problema lasciando che le funzioni siano banalmente "referenzialmente trasparenti".

  • Tratta l'intero programma come una singola funzione pura prendendo "tutto l'input ricevuto" come argomento e restituendo "tutto l'output prodotto", con entrambi rappresentati da una qualche forma di flusso lento per consentire l'interattività.

Ci sono una varietà di modi per implementare entrambi gli approcci, così come un certo grado di sovrapposizione - ad esempio, nel secondo caso, le funzioni operanti sulla I/O stream è improbabile che siano chiamati due volte con la stessa parte del flusso. Il modo di guardarlo ha più senso dipende dal tipo di supporto che il linguaggio ti offre.

In Haskell, IO è un tipo di monade che si infila automaticamente stato sequenziale attraverso il codice (simile al funzionalmente pura State monade), tale che, concettualmente, ogni chiamata a una funzione impura ottiene un diverso valore della implicito "stato del mondo esterno".

L'altro approccio popolare che conosco utilizza qualcosa come linear types a un fine simile; assicurando che le funzioni impure non ottengano mai gli stessi argomenti due volte avendo valori che non possono essere copiati o duplicati, in modo che i vecchi valori dello "stato del mondo esterno" non possano essere tenuti in giro e riutilizzati.

5

Imperative Functional Programming di Peyton Jones e Wadler è una lettura obbligata se si è interessati all'IO funzionale. Gli altri approcci che si discutono sono:

  • dialoghi che sono i flussi pigri di risposte e richieste

type Dialogue = [Response] -> [Request]

main :: Dialogue

  • Continuazioni - ogni operazione IO prende una continuazione come argomento

  • Tipi lineari: il tipo di sistema ti impedisce di copiare o distruggere lo stato esterno, il che significa che non puoi chiamare una funzione due volte con lo stesso stato.

3

Functional Reactive Programming è un altro modo per gestire questo.

+1

Non ho mai sentito il termine "Funzione Programmazione reattiva". Puoi cambiarlo in "Functional Reactive Programming"? Ottima risposta altrimenti. –

+0

Nessun problema, grazie per aver notato. Non ho idea di come ho sbagliato a scrivere quello. –

Problemi correlati