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.