STDOUT e la sua impurità

10

Ho letto molti libri e articoli sulla programmazione funzionale e mi vergogno ancora di non riuscire a capire di sicuro alcuni concetti di base.

Una delle idee principali della programmazione funzionale è che lo stesso input dovrebbe sempre produrre lo stesso output. Pertanto, per esempio, non è possibile eseguire query sul database o sul file di scrittura in uno stile puramente funzionale per definizione. Questo è, ad esempio, uno dei motivi per cui abbiamo bisogno di monadi.

La domanda è: perché consideriamo l'output di STDOUT come qualcosa di impuro? Sì, qualsiasi gestore di file è rischioso - non possiamo mai essere sicuri che i dati verranno sempre scritti. Ma per quanto riguarda STDOUT? Perché dovremmo pensarci come qualcosa di inaffidabile? È più inaffidabile la valutazione stessa? Voglio dire, possiamo sempre premere il grilletto e quindi interrompere il calcolo.

    
posta shabunc 15.09.2011 - 15:53
fonte

4 risposte

6

Therefore, say, querying database or writing file could not be done in a pure functional style by definition. That's for example, is one of reasons we need monads.

Nessuno "ha bisogno" di monadi, questo è solo un modo per descrivere le cose. In realtà, probabilmente non è nemmeno il modo migliore. Qualche forma di digitando , unicità tipi , o un sistema basato sulla logica lineare completa sembrano più persuasivi in teoria, ma sono tutte le differenze più radicali da sistemi di tipi ben noti e più complicati da esprimere. L'I / O monodico trovato in Haskell è un compromesso tra usabilità e semplicità, dal momento che essenzialmente modella la programmazione assolutamente imperativa in un modo che coesiste facilmente con il sistema di tipo esistente in stile ML già utilizzato nella lingua.

The question is - why we consider STDOUT output as something impure? Yes, any filehandler is risky - we never can be sure that data always will be written. But what about STDOUT? Why should we think of it as of something unreliable? Is it more unreliable that evaluation itself? I mean, we always can pull the trigger and thus, interrupt calculation.

Non lo è, e non lo facciamo. L'input e l'output da, il programma nel suo insieme possono essere semplicemente considerati come argomenti e risultati dal considerare l'intero programma come una grande funzione pura. Fintanto che stampa la stessa cosa sullo stdout se lo si nutre della stessa cosa da stdin, è pur sempre una funzione pura. Infatti, prima di introdurre l'IO monadico, Haskell usava un sistema di I / O basato sul flusso che utilizzava flussi pigri puri per l'input e l'output. L'ha lasciato cadere perché era apparentemente un dolore da usare, il che potrebbe darti un'idea del perché non hai sentito nulla di simile. :]

Per rendere il punto più sciocco, considera il linguaggio esoterico minimalista, Lazy K :

Lazy K is a garbage-collected, referentially transparent functional programming language, with a simple stream-based I/O system.

What distinguishes Lazy K from other such languages is its almost total lack of other features. It does not, for example, offer an integrated Hindley-Milner polymorphic type system. It is not shipped with an extensive standard library with support for platform-independent GUI programming and bindings to other languages. Nor could any such library be written since, among other things, Lazy K does not provide any way to define or refer to any functions other than built-ins. This inability is complemented by a matching lack of support for numbers, strings, or any other data type. Nevertheless, Lazy K is Turing-complete.

(...)

Lazy K programs live in the same timeless Platonic realm as mathematical functions, what the Unlambda page calls "the blessed realm of the pure untyped lambda calculus." Just as garbage collection hides the process of memory management from the programmer, so referential transparency hides the process of evaluation. The fact that some calculation is necessary in order to view a picture of the Mandelbrot set, or in order to "run" a Lazy K program, is an implementation detail. That's the essence of functional programming.

(...)

How to handle input and output in a language without side effects? In a certain sense, input and output aren't side effects; they are, so to speak, front- and back-effects. So it is in Lazy K, where a program is simply treated as a function from the space of possible inputs to the space of possible outputs.

Dubito che troverai un linguaggio più puramente funzionale!

Tenete a mente, tuttavia, che quanto sopra si applica solo essenzialmente prendendo l'input e l'output di una funzione pura e collegandoli a stdin / stdout "esternamente" in qualche modo. C'è una grande differenza tra questo e l'accesso alle primitive di I / O reali a livello di sistema. I dettagli di implementazione della lettura e della scrittura sui flussi possono perdere impurità se non attentamente incapsulati.

Mi aspetto che questo sia il motivo principale per cui non è possibile farlo direttamente in Haskell - i casi di utilizzo ragionevoli sono ridotti rispetto all'utilizzo di IO monadico e per quest'ultimo è molto vantaggioso avere accesso alla cosa reale . Credo che sia per questo che, ad esempio, gli argomenti della riga di comando per il programma non vengono semplicemente passati come argomenti a main , anche se sembra intuitivo che dovrebbero essere.

Puoi recuperare una versione minima di qualcosa di simile in un programma specifico, però - acquisisci gli argomenti come valori puri e poi usa la funzione interact per il resto del programma.

    
risposta data 15.09.2011 - 16:19
fonte
3

Mentre la purezza in un programma funzionale è un obiettivo degno, la realtà è che ogni programma non banale e utile avrà qualche impurità (o "effetti collaterali"), per le ragioni che hai menzionato.

I programmi completamente puri sono, per definizione, una scatola nera sigillata, e sono essenzialmente poco interessanti.

Il linguaggio funzionale Haskell si prende cura di questo problema isolando gli effetti collaterali come l'output in monadi . La monade conserva uno stile puramente funzionale di programmazione, pur rendendo possibile la produzione di output.

    
risposta data 15.09.2011 - 15:59
fonte
1

La scrittura su STDOUT può fallire se non sei connesso a un dispositivo terminale o se (per qualche motivo) hai chiuso il descrittore di file per esso.

Inoltre, STDOUT non è sempre "lo schermo della console". A volte viene inviato a un altro programma. A volte il tubo è rotto.

    
risposta data 15.09.2011 - 17:38
fonte
0

Aiuta se pensi alla purezza in termini di "Cambia lo stato del mondo esterno". Ciò potrebbe includere la scrittura su una console, il file di registro, l'espulsione del CD o "Avvio dei missili".

Può anche essere un problema in termini di esecuzione simultanea. Se sai che una funzione non ha effetti collaterali, puoi facilmente organizzare una concorrenza in quanto puoi provare che non ci possono essere condizioni di gara o simili.

    
risposta data 15.09.2011 - 18:55
fonte

Leggi altre domande sui tag