Difference between revisions of "The I/O problem"
m |
m |
||
(105 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
+ | <!-- Note: only add supporting content dated up to 2017 (i.e. before the online existence of this content, both here and elsewhere). --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | Haskell uses the seriously complex machinery of monads to do I/O, supposedly without side effects (I don't accept this). And you end up writing stuff [...] which to me looks like C. There must be a more functional approach. |
||
+ | <blockquote> |
||
− | <tt>[https://billwadge.wordpress.com/2021/05/22/monads-schmonads-functional-input-without-tears-pyfl Monads Schmonads: Functional Input without tears (PyFL)], Bill Wadge.</tt><!-- 2021 --> |
||
+ | Functional languages are entirely mathematical, so the places where they don't work |
||
− | </div> |
||
+ | show where computing is not mathematics and help to illuminate both fields. |
||
− | <br> |
||
+ | :<small>[http://www.bitsavers.org/pdf/xerox/parc/techReports/CSL-81-11_Real_Programming_in_Functional_Languages.pdf Real Programming in Functional Languages], James H. Morris (page 33 of 36).</small><!-- 1981 --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | [...] In the [http://conal.net/blog/posts/the-c-language-is-purely-functional pure functional] languages, Haskell and Clean, at present the most developed ones, the I/O problem is solved by respectively monads and uniqueness typing. But using these features, in both cases it is still possible to write incomprehensible code when dealing with I/O. |
||
+ | One of those places is I/O: |
||
− | <tt>[https://lmcs.episciences.org/6755/pdf Gems of Corrado Böhm], Henk Barendregt.</tt><!-- 2020 --> |
||
− | </div> |
||
− | <br> |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | For Turing's [automatic] machine, a calculation begins with a problem on its tape, and ends with an |
||
− | Fundamentally, all functional languages are translated to an imperative language, and it leaks. |
||
+ | answer there. For Church's calculus, reduction begins with a lambda term, and ends |
||
+ | with its normal form. For Floyd's flowcharts and Hoare's triples, a program begins |
||
+ | in a state satisfying a precondition, and ends in a state satisfying a postcondition. |
||
+ | How the initial tape or term or state is input, and how the final one is output, are |
||
+ | questions neither asked nor answered. |
||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.91.3579&rep=rep1&type=pdf How to Declare an Imperative], Philip Wadler (pages 1-2 of 33).</small><!-- 1997 --> |
||
− | It leaks when you need to read and write files, when you need to respond to real-time user events, when you write to the screen or interact with the GPU, or when you communicate with an external process or API. |
||
+ | </blockquote> |
||
+ | __TOC__ |
||
− | <tt>[https://myowenopinion.com/post/dev/functional-programming-is-a-leaky-abstraction Functional Programming Is a Leaky Abstraction], Owen Merkling.</tt> |
||
− | <!-- 2020 --> |
||
− | </div> |
||
− | <br> |
||
+ | == The problem is mathematical in origin == |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | This is hard stuff. Two years ago I spent several hours to write 3 lines invoking IO computations. |
||
+ | The various fields of study collectively referred to as <i>mathematics</i> are abstract in one or more ways: |
||
− | <tt>[https://discourse.haskell.org/t/trying-to-understand-the-io/1172/8 Trying to understand the <code>IO ()</code>], ''"belka"''.</tt><!-- 2020 --> |
||
− | </div> |
||
− | <br> |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | In a preliminary sense, mathematics is abstract because it is studied using highly general and formal resources. |
||
− | [...] Essentially, the Haskell type <code>IO t</code> combines both the features of [Idealised Algol's] <code>comm</code> and <code>exp</code>. This makes the [Haskell] framework slightly simpler, but it can be cumbersome if imperative computations are performed extensively. [...] |
||
+ | :<small>[https://iep.utm.edu/math-app The Applicability of Mathematics], from the [https://iep.utm.edu/ Internet Encyclopedia of Philosophy].</small> |
||
− | <tt>[https://www.cs.bham.ac.uk/~udr/popl/09-17-Algol-like.pdf Handout 9: Imperative programs and the Lambda Calculus], Uday Reddy.</tt><!-- 2018 --> |
||
− | </ |
+ | </blockquote> |
− | <br> |
||
+ | For a declarative programming language like Haskell, which is based on one of these individual fields of study - higher-order functions - being so abstract then raises the question of I/O and its observable effects: |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | [...] I like the concise way of coding pure functions in Haskell using mathematical ideas like recursion and list comprehensions. However, user interactions are quite painful to implement using the I/O monad. [...] |
||
+ | <blockquote> |
||
− | <tt>[https://www.linkedin.com/pulse/definition-functional-programming-rainer-grimm The Definition of Functional Programming], Dirk Verlinden.</tt><!-- 2017 --> |
||
+ | How must interactions between a program and an external environment |
||
− | </div> |
||
+ | (consisting of, e.g., input/output-devices, file systems, ...) be described in |
||
− | <br> |
||
+ | a programming language that abstracts from the existence of an outside world? |
||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.95.9846&rep=rep1&type=pdf Functions, Frames and Interactions], Claus Reinke (page 10 of 210).</small><!-- 1998 --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | <code>IO</code> is indeed a monad instance, but not a very nice one - the compiler treats it specially, and it is not very nice to reason about [...] |
||
+ | and effects more generally, with a preference for a denotational (as opposed to [[Monad_tutorials_timeline|inexplicable]]) semantics: |
||
− | <tt>[https://nickhu.co.uk/Monads.pdf Understanding Monads], Nick Hu.</tt><!-- 2016 --> |
||
− | </div> |
||
− | <br> |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | During the 1960s, several researchers began work on proving things about programs. [...] |
||
− | Haskell compromises brilliantly, by fencing off pure and impure functions from one another [...] The illusion is so good that programmers are fooled into thinking I/O is pure in Haskell. And now that we can write mostly pure code with occasional impure wrappers, researchers have mostly stopped seeking superior alternatives. |
||
+ | Several difficult problems emerged from this work. One was the problem of <i>specification</i>: before |
||
− | <tt>[https://crypto.stanford.edu/~blynn/haskell/io.html A Problem With I/O], Ben Lynn.</tt><!-- 2016 --> |
||
+ | one can prove that a program is correct, one must specify the meaning of "correct", formally and |
||
− | </div> |
||
+ | unambiguously. Formal systems for specifying the meaning of a program were developed, and they |
||
− | <br> |
||
+ | looked suspiciously like programming languages. |
||
+ | Researchers began to analyze why it is often harder to prove things about programs written in |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | traditional languages than it is to prove theorems about mathematics. Two aspects of traditional |
||
− | [...] you shouldn't spend much time writing <code>IO</code> stuff, because it's a bad language embedded in a good one. |
||
+ | languages emerged as sources of trouble because they are very difficult to model in a mathematical |
||
+ | system: mutability and sequencing. |
||
+ | :<small>[https://core.ac.uk/download/pdf/214330064.pdf The Anatomy of Programming Languages], Alice E. Fischer and Frances S. Grodzinsky (page 353 of 600).</small><!-- 1993 --> |
||
− | <tt>[https://web.archive.org/web/20220309052143/http://comonad.com/reader/2015/on-the-unsafety-of-interleaved-io On the unsafety of interleaved I/O], Dan Doel.</tt><!-- 2015 --> |
||
− | </ |
+ | </blockquote> |
− | <br> |
||
+ | * mutability: |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | IO in Haskell [is] for me a source of great displeasure and it just defeated every try I have given to learn the language. |
||
+ | <blockquote> |
||
− | <tt>[https://www.haskellforall.com/2013/01/introduction-to-haskell-io.html?showComment=1361296801442#c794624017122358881 Introduction to Haskell <code>IO</code>], Ludovic Kuty.</tt><!-- 2013 --> |
||
+ | There is <i>in principle</i> nothing to stop functional programs from |
||
− | </div> |
||
+ | passing a single extra parameter into and out of every single function in the |
||
− | <br> |
||
+ | entire system. If this extra parameter were a collection (compound value) |
||
+ | of some kind then it could be used to <i>simulate</i> an arbitrarily large set of |
||
+ | mutable variables. In effect this approach recreates a single pool of global |
||
+ | variables - hence, even though referential transparency is maintained, ease |
||
+ | of reasoning is lost (we still know that each function is dependent only upon |
||
+ | its arguments, but one of them has become so large <i>and contains irrelevant |
||
+ | values</i> that the benefit of this knowledge as an aid to understanding is |
||
+ | almost nothing). |
||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.93.8928&rep=rep1&type=pdf Out of the Tar Pit], Ben Moseley and Peter Marks (page 17 of 66).</small><!-- 2006 --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | Stream transformers are fragile to use, continuations are powerful but somewhat clutter the syntax of functions. Monads and uniqueness types both present a trade-off, do we accept the over-sequentialisation imposed by monads, or the visual disorder of explicit environment passing? We believe that a compromise is still to be found [...] |
||
+ | * sequencing: |
||
− | <tt>[https://www.owenstephens.co.uk/assets/static/research/masters_report.pdf Approaches to Functional I/O], Owen Stephens.</tt><!-- 2011 --> |
||
− | </div> |
||
− | <br> |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | We have experimented for some time with a means for the programmer to specify a |
||
− | Once you’re in the IO monad, you’re stuck there forever, and are reduced to Algol-style imperative programming. You cannot easily convert between functional and monadic style without a radical restructuring of code. |
||
+ | ‘syntactic’ partial order between subexpressions, with the intended effect that the ‘semantic’ |
||
+ | order in which the input actions occur during the evaluation is not in conflict with the specified |
||
+ | ‘syntactic’ partial order on the subexpressions (which carries over to the input actions evoked |
||
+ | by those subexpressions). As a consequence, whenever the evaluator is about to execute an |
||
+ | input action, it first has to decide whether there will occur in the future another input action |
||
+ | that should be done first according to the specified ‘syntactic’ partial order. That problem, |
||
+ | however, is undecidable. |
||
+ | :<small>[https://maartenfokkinga.github.io/utwente/mmf2001c.pdf An alternative approach to I/O], Maarten Fokkinga and Jan Kuper (page 6 of 12).</small><!-- 2001 --> |
||
− | <tt>[https://existentialtype.wordpress.com/2011/05/01/of-course-ml-has-monads Of Course ML Has Monads!], Robert Harper.</tt><!-- 2011 --> |
||
− | </ |
+ | </blockquote> |
− | <br> |
||
+ | === The technical difficulty === |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | Functional programmers used to worry about how to solve “the I/O problem”. Functional programming (FP) eschews any notion of side-effect or order of ''execution'', and instead has an order-independent notion of ''evaluation''. In contrast, input & output (I/O) seems to be an inherently effectful, ordered notion. |
||
+ | [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.144.2237&rep=rep1&type=pdf In 1994] researchers showed that mutability and sequencing, if restricted, could be used anonymously in Haskell: |
||
− | [...] |
||
+ | <blockquote> |
||
− | In a sense, I see us as in a worse position than before. Since the adoption of monadic <code>IO</code>, it’s been less immediately apparent that we’re still enslaved [...] Our current home is not painful enough to goad us onward, as were continuation-based I/O and stream-based I/O. (See [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.168.4008&rep=rep1&type=pdf A History of Haskell], section 7.1.) Nor does it fully liberate us. |
||
+ | The reason for introducing a <i>different</i> monad <code>ST</code>, rather than just providing |
||
+ | these operations over the <code>IO</code> monad, is that destructive updates to variables in |
||
+ | a program are not <i>externally visible</i> side-effects. We can therefore encapsulate |
||
+ | these imperative effects [...] Using <code>runST</code> we can write pure (non-monadic) functions |
||
+ | whose implementation uses imperative features internally. |
||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.697.6499&rep=rep1&type=pdf Monads and Effects], Nick Benton, John Hughes and Eugenio Moggi (pages 33-34 of 82).</small><!-- 2002 --> |
||
− | <tt>[http://conal.net/blog/posts/can-functional-programming-be-liberated-from-the-von-neumann-paradigm Can functional programming be liberated from the von Neumann paradigm?], Conal Elliott.</tt><!-- 2010 --> |
||
− | </ |
+ | </blockquote> |
− | <br> |
||
+ | So I/O is a problem because of its external visibility, and that visibility demands the side effects of I/O have the appropriate sequencing: |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | [...] Support for [external] state in Haskell exists in the form of the I/O monad[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.9725&rep=rep1&type=pdf <span></span>], but in our opinion the monadic idiom does not scale well to large, complexly stateful programs, and imposes constraints that are unnatural in the eyes of systems programmers. |
||
+ | <blockquote> |
||
− | <tt>[https://web.archive.org/web/20081212233905/http://www.bitc-lang.org/docs/bitc/bitc-origins.html The Origins of the BitC Programming Language], Jonathan Shapiro, Swaroop Sridhar and M. Scott Doerrie.</tt><!-- 2008 --> |
||
+ | By introducing <i>side effects</i> in expressions, the semantics becomes |
||
− | </div> |
||
+ | significantly more complex. At the same time, several issues arise, |
||
− | <br> |
||
+ | related to the <i>evaluation order</i>, i.e. the order in which the subparts of |
||
+ | an expression are evaluated. If the evaluation order is not strictly defined, |
||
+ | the presence of side effects in expressions is a source of non-deterministic |
||
+ | behaviour. |
||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.38.9189&rep=rep1&type=pdf Denotational Semantics of Evaluation Order in Expressions with Side Effects], Nikolaos S. Papaspyrou (first page).</small><!-- 1998 --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | [...] the next question that always comes up is how to do IO down in an function (in an expression) down a ways in the code. This often involves rewriting those "expressions" into "commands". |
||
+ | <blockquote> |
||
− | <tt>[http://blog.sigfpe.com/2007/11/io-monad-for-people-who-simply-dont.html#6353382341670425040 The IO Monad for People who Simply Don't Care], ''"jefu"''.</tt><!-- 2007 --> |
||
+ | When combining effects, |
||
− | </div> |
||
+ | their order is often highly important (the reader might want to try different |
||
− | <br> |
||
+ | combinations of the effects “Open door”, and “Walk through door”, for example). |
||
+ | :<small>[https://cth.altocumulus.org/~hallgren/Thesis/fudgets_thesis_color.pdf Fudgets – Purely Functional Processes with applications to Graphical User Interfaces], Magnus Carlsson and Thomas Hallgren (page 12 of 263).</small><!-- 1998 --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | <b>Booch</b>: What would be your advice to somebody that would want to take up the banner of functional programming? Where would you suggest they begin, and what hard problems would you like them to pursue? |
||
+ | ...and the machinery which runs our programs relies on mutability: |
||
− | <b>Backus</b>: Well, trying to functionalize all the input/output stuff. |
||
+ | <blockquote> |
||
− | <b>Booch</b>: Helping it talk to the real world. |
||
+ | An “automatic” machine becomes a “choice” machine as soon as we allow the machine’s tape |
||
+ | to be modified by external entities: the tape itself becomes a means of communication. This is |
||
+ | essentially what happens in “real” computers (memory-mapped I/O); for example, we can write |
||
+ | to the computer’s screen by modifying one particular area of memory, or find out which key was |
||
+ | pressed on the computer’s keyboard by reading another. |
||
+ | It is less obvious how to add interaction to the lambda calculus. |
||
− | <b>Backus</b>: Yes. |
||
+ | :<small>[http://edsko.net/pubs/thesis.pdf Making Uniqueness Typing Less Unique], Edsko de Vries (page 23 of 264).</small><!-- 2008 --> |
||
− | <tt>[https://archive.computerhistory.org/resources/text/Oral_History/Backus_John/Backus_John_1.oral_history.2006.102657970.pdf Oral History of John Backus], Grady Booch.</tt><!-- 2006 --> |
||
− | </ |
+ | </blockquote> |
− | <br> |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | Stream transformers are fragile to use, continuations are powerful |
||
− | A recognised difficulty with using monads to enforce single-threaded access to the I/O world is that the programmer is forced to over-sequentialize their I/O code: I/O operations that are independent and which could be performed in any order still need to be given an explicit ordering in the program. |
||
+ | but somewhat clutter the syntax of functions. Monads and |
||
+ | uniqueness types both present a trade-off, do we accept |
||
+ | the over-sequentialisation imposed by monads, or the visual |
||
+ | disorder of explicit environment passing? We believe that a |
||
+ | compromise is still to be found [...] |
||
− | < |
+ | :<small>[https://www.owenstephens.co.uk/assets/static/research/masters_report.pdf Approaches to Functional I/O], Owen Stephens (final page).</small><!-- 2011 --> |
− | </ |
+ | </blockquote> |
− | <br> |
||
+ | Using prior research: |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | The downside of I/O using monads is the need for a monad that can not be unwrapped. So, when using monadic I/O there is no way to get rid of the I/O monad. Furthermore, it is not as intuitive as one would like it to be. A prerequisite to good software design is a thorough understanding of the structures and glues of the implementation language. [...] Yet the understanding of monads is not trivial. The extensive amount of tutorials and questions on the Internet strengthen this thought. |
||
+ | <blockquote> |
||
− | <tt>[https://essay.utwente.nl/57287/1/scriptie_Rorije.pdf Input/Output in Functional Languages (Using Algebraic Union Types)], R.J. Rorije.</tt><!-- 2006 --> |
||
+ | The theory of relative computability developed by Turing and Post and |
||
− | </div> |
||
+ | the <i>o</i>-machines provide a precise mathematical framework for interactive |
||
− | <br> |
||
+ | or online computing just as Turing <i>a</i>-machines provide one for offline |
||
+ | computing processes such as batch processing. |
||
+ | :<small>[http://www.people.cs.uchicago.edu/~soare/Turing/shagrir.pdf Turing-Post Relativized Computability and Interactive Computing], Robert Irving Soare (page 7 of 76).</small><!-- 2011 --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | [...] doing IO in Haskell means using a polymorphic type as well as a mathematical theory that is rather obtuse. That's why IO is so far down in this tutorial. |
||
+ | a more satisfactory solution could be obtained. Another possibility is a completely-new discovery: the investigation [http://conal.net/blog/posts/can-functional-programming-be-liberated-from-the-von-neumann-paradigm#comment-598 continues]. In the meantime, those who work with programming languages will have to contend with I/O as best they can: |
||
− | <tt>[https://web.archive.org/web/20160408094723/http://www.kt.rim.or.jp/~kbk/haskell-intro/section3.html#part7 Haskell Tutorial for C Programmers], Eric Etheridge.</tt><!-- 2005 --> |
||
− | </div> |
||
− | <br> |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | By its very nature I/O does not fit in well |
||
− | The common method to relieve the programming language designer from the inherent IO-problems is to shift responsibility to the programmer who has to sequentialize all IO-requests. This is also true for the monadic approach implemented in Haskell. |
||
+ | with programming language design. Every language |
||
+ | designer has encountered the problem that the task of |
||
+ | including usable I/O facilities invariably seems to make it |
||
+ | necessary to break some of the rules or design principles |
||
+ | of the language. In many languages with clean and |
||
+ | simple concepts I/O is the "odd one out". |
||
− | < |
+ | :<small>[https://www.cs.kent.ac.uk/pubs/1997/2176/content.pdf I/O Considered Harmful (At Least for the First Few Weeks)], John Rosenberg and Michael Kölling (first page).</small><!-- 1997 --> |
− | </ |
+ | </blockquote> |
− | <br> |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | [...] I/O calls are side effects and make impure functions. Impure functions |
||
− | The notation for interactive programs written in the monadic style is irritatingly close to the notation used in imperative languages.<br> |
||
+ | are hard to test. |
||
− | [...]<br> |
||
− | Uniqueness typing addresses the more general problem of statically controlled use of resources in functional programs and, even if combined with passing unique representations of environment objects as arguments to these programs, it does not suffice to solve the input/output-problem. [...] The reason is that the environment is not updated in one conceptual step after the evaluation of a program [...] but rather in small steps whenever the environment representation is modified during program evaluation. The primitive interactions are thus implemented as side-effecting operations, the use of which is rendered safe in the uniqueness-typed environment passing framework. |
||
− | <br> |
||
− | [...]<br> |
||
− | Similarly, monads are used to address the more general problem of computations (involving state, input/output, backtracking, ...) returning values: they do not solve any input/output-problems directly but rather provide an elegant and flexible abstraction of many solutions to related problems. [...] For instance, no less than three different input/output-schemes are used to solve these basic problems in [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.9725&rep=rep1&type=pdf Imperative functional programming], the paper which originally proposed `a new model, based on monads, for performing input/output in a non-strict, purely functional language'.<br> |
||
− | [...]<br> |
||
− | So, both input/output-schemes merely provide frameworks in which side-effecting operations can safely be used with a guaranteed order of execution and without affecting the properties of the purely functional parts of the language. |
||
− | < |
+ | :<small>[https://refactoringjs.com/files/refactoring-javascript.pdf Refactoring JavaScript], Evan Burchard (page 437 of 499).</small><!-- 2017 --> |
− | </ |
+ | </blockquote> |
− | <br> |
||
+ | ...especially considering the ever-expanding state space in which memory-mapped I/O resides: |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | How can we integrate interaction into a purely declarative language?<br> |
||
− | [...]<br> |
||
− | For Turing's machine, a calculation begins with a problem on its tape, and ends with an answer there. For Church's calculus, reduction begins with a lambda term, and ends with its normal form. For Floyd's flowcharts and Hoare's triples, a program begins in a state satisfying a precondition, and ends in a state satisfying a postcondition. How the initial tape or term or state is input, and how the final one is output, are questions neither asked or answered. |
||
+ | <blockquote> |
||
− | <tt>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.91.3579&rep=rep1&type=pdf How to Declare an Imperative], Philip Wadler.</tt><!-- 1997 --> |
||
+ | <b>Definition 6.1.</b> A <i>state</i> is an element of 2<sup><i>n</i></sup> for some fixed <i>n</i>; that is, it is a finite |
||
− | </div> |
||
+ | sequence of 1s and 0s. The space 2<sup><i>n</i></sup> is called the <i>state space</i>. |
||
− | <br> |
||
+ | The number <i>n</i> is the size of the memory in bits, and will usually be rather large. |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | On modern personal computers at the time of this writing, <i>n</i> would be on the order |
||
− | While it is fine that monadic I/O has good theoretical under-pinnings, did anyone stop to think if it helped in user interface programming? If all that it is is a means <i>somehow</i> to construct interactive programs, then it succeeds, but that is not enough. A programmer chooses a language based not on only on ability, but also usability. |
||
+ | of several billion. |
||
− | < |
+ | :<small>[https://math.uchicago.edu/~may/VIGRE/VIGRE2011/REUPapers/Berger.pdf On Some Aspects of The Theory of Monads], Carsen Berger (page 14 of 16).</small><!-- 2011 --> |
− | </ |
+ | </blockquote> |
− | <br> |
||
+ | == An axiomatic approach == |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | The programming style in a lazy functional language is heavily influenced by the supported I/O-mechanism. Modifying the I/O-behaviour or debugging some lazy functional program that uses I/O is a black art. It is interesting that novices in lazy functional programming in general expect that there is some direct (side-effecting) I/O using a function call. |
||
+ | The dependently-typed language Agda relies on Haskell for its outside interactions: |
||
− | <tt>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.55.1076&rep=rep1&type=pdf A Partial Rehabilitation of Side-Effecting I/O:], Manfred Schmidt-Schauß.</tt><!-- 1996 --> |
||
− | </div> |
||
− | <br> |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | <b>4 Compiling Agda programs</b> |
||
− | Although the advantages of functional programming are fairly well known, a few areas have proved troublesome, I/O being one of these. [...] |
||
+ | This section deals with the topic of getting Agda programs to interact |
||
− | <tt>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.38.2254&rep=rep1&type=pdf Functional Languages and Graphical User Interfaces - a review and a case study], Rob Noble and Colin Runciman.</tt><!-- 1994 --> |
||
+ | with the real world. Type checking Agda programs requires evaluating |
||
− | </div> |
||
+ | arbitrary terms, ans as long as all terms are pure and normalizing this is |
||
− | <br> |
||
+ | not a problem, but what happens when we introduce side effects? Clearly, |
||
+ | we don't want side effects to happen at compile time. Another question is |
||
+ | what primitives the language should provide for constructing side effecing |
||
+ | programs. In Agda, these problems are solved by allowing arbitrary |
||
+ | Haskell functions to be imported as axioms. At compile time, these imported |
||
+ | functions have no reduction behaviour, only at run time is the |
||
+ | Haskell function executed. |
||
+ | :<small>[http://www.cse.chalmers.se/~ulfn/papers/afp08/tutorial.pdf Dependently Typed Programming in Agda], Ulf Norell and James Chapman (page 38 of 41).</small><!-- 2008 --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | Although we all love the beautiful aspects of functional languages we must admit that it is difficult to deal with a beast called Input-Output (I/O). |
||
+ | Haskell's FFI also allows for arbitrary foreign code to be imported, to only be executed at run time: |
||
− | <tt>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.43.6060&rep=rep1&type=pdf The Beauty and the Beast], Peter Achten and Rinus Plasmeijer.</tt><!-- 1992 --> |
||
− | </div> |
||
− | <br> |
||
+ | <haskell> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | instance Monad IO where |
||
− | One consequence of referential transparency is that it is difficult to incorporate I/O into a pure functional language. At least, the mechanism familiar to imperative programmers, say, a function of no arguments [...] which returns the next data item of a stream, would be impossible, since successive calls [...] ought to return different values. Alternative models have been proposed which do not suffer from this difficulty [...] Nonetheless, these other models are notationally complex, and I/O [modelling] remains a problem. |
||
+ | return = unitIO |
||
+ | (>>=) = bindIO |
||
+ | |||
+ | foreign import ccall "primUnitIO" unitIO :: a -> IO a |
||
+ | foreign import ccall "primBindIO" bindIO :: IO a -> (a -> IO b) -> IO b |
||
+ | ⋮ |
||
+ | </haskell> |
||
− | + | However, Haskell 2010 doesn't allow higher-order FFI declarations, or their use of type variables. Visible implementations of monadic I/O [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.91.3579&rep=rep1&type=pdf based on other interfaces] are another option, but Haskell 2010 also imposes restrictions on its I/O type: |
|
− | </div> |
||
− | <br> |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | The <code>IO</code> type serves as a tag for operations (actions) that interact with the outside world. The <code>IO</code> type is |
||
− | [...] A straightforward example of such a problematical application is that of a function which could allow us to interactively query and modify a database; this is clearly an interactive problem, since we may only be able to formulate queries once we have seen the responses to earlier ones. |
||
+ | abstract: no constructors are visible to the user. |
||
− | < |
+ | :<small>[https://www.haskell.org/definition/haskell2010.pdf The Haskell 2010 Report] (page 95 of 329).</small><!-- 2010 --> |
− | </ |
+ | </blockquote> |
− | <br> |
||
+ | == On being denotative == |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | [...] Is there any hope of achieving <i>purely functional</i>, yet <i>universal</i>, and of course <i>efficient</i> I/O? |
||
+ | While the [https://okmij.org/ftp/Computation/IO-monad-history.html prevailing] approach to I/O is based on combining the imperative and functional programming styles: |
||
− | <tt>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.49.695&rep=rep1&type=pdf On the Expressiveness of Purely Functional I/O Systems], Paul Hudak and Raman S. Sundaresh.</tt><!-- 1989 --> |
||
− | </div> |
||
− | <br> |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | The special claim of <tt>ISWIM</tt> is that it grafts procedural |
||
− | [...] many I/O schemes have been proposed for purely functional languages, but they tend to be <i>ad hoc</i> in the sense of being designed to express particular kinds of I/O, without aiming for universal power. [...] |
||
+ | notions onto a purely functional base without disturbing |
||
+ | many of the desirable properties. |
||
− | < |
+ | :<small>[https://dl.acm.org/doi/pdf/10.1145/365230.365257 The Next 700 Programming Languages], Peter J. Landin (page 8 of 10).</small><!-- 1966 --> |
− | </ |
+ | </blockquote> |
− | <br> |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | We need the concept of a ‘process’ as opposed to a function. Intuitively a |
||
− | Functional languages are extremely powerful and succinct tools for expressing algorithms[https://www.cambridge.org/9780521245036 <span></span>], but the way in which the results of such calculations should be communicated to the outside world is not obvious. [...] |
||
+ | process is something that (in general) is geared towards continuation while a |
||
+ | function is geared towards termination. Processes have an input channel on |
||
+ | which an input stream (a potentially infinite sequence of tokens) is coming |
||
+ | in and an output channel on which an output stream is coming out. A |
||
+ | typical process is the control of a traffic light system: it is geared towards |
||
+ | continuation, there is an input stream (coming from the pushbuttons for |
||
+ | pedestrians) and an output stream (regulating the traffic lights). Text editing |
||
+ | is also a process. In fact, even the most simple form of I/O is already a |
||
+ | process. |
||
+ | :<small>[https://repository.ubn.ru.nl/bitstream/handle/2066/17274/13362.pdf The impact of the lambda calculus in logic and computer science], Henk Barendregt (page 21 of 36).</small><!-- 1997 --> |
||
− | <tt>[https://core.ac.uk/download/pdf/82449736.pdf Message-based functional operating systems], Willian Stoye.</tt><!-- 1986 --> |
||
− | </ |
+ | </blockquote> |
− | <br> |
||
+ | which is achieved in Haskell [https://dl.acm.org/doi/pdf/10.1145/319838.319848 by using types]: |
||
− | __TOC__ |
||
+ | <blockquote> |
||
− | == The I/O problem is mathematical in origin == |
||
+ | The main program |
||
+ | (function <code>main</code> from module <code>Main</code>, which |
||
+ | we write <code>Main.main</code>) has type <code>IO ()</code>, that is, it |
||
+ | is a computation which performs some I/O and |
||
+ | returns an uninteresting result. The "trivial" |
||
+ | type <code>()</code> has only one value, the unit value, which |
||
+ | is also written <code>()</code>. |
||
+ | :<small>[https://web.archive.org/web/20080325064317/http://www-fp.dcs.st-and.ac.uk/~kh/papers/io-tutorial/section3_2.html#SECTION0002000000000000000 Monadic I/O in Haskell 1.3], Andrew D. Gordon and Kevin Hammond.</small><!-- 1996 --> |
||
− | The various fields of study collectively referred to as <i>mathematics</i> are abstract in one or more ways: |
||
+ | </blockquote> |
||
+ | ...there has also been interest in using denotational semantics or models due to the advantages they provide: |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | In a preliminary sense, mathematics is abstract because it is studied using highly general and formal resources. |
||
+ | <blockquote> |
||
− | <tt>[https://iep.utm.edu/math-app The Applicability of Mathematics], from the [https://iep.utm.edu/ Internet Encyclopedia of Philosophy].</tt> |
||
+ | For example, there |
||
− | </div> |
||
+ | are several simple variations on the model for processes [[https://dl.acm.org/doi/pdf/10.1145/322123.322134 <span></span>]]. |
||
+ | In the face of such an abundance, it is best to recall the motivation for seeking |
||
− | In particular, they abstract away from the presence of an outside environment. For a declarative programming language like Haskell, which is based on one of these individual fields of study - higher-order functions - this raises the question of I/O and its observable effects: |
||
+ | such models. They provide a useful mathematical framework for the analysis of |
||
+ | programs, and for developing logical systems for proving their properties. |
||
+ | :<small>[https://www.scss.tcd.ie/Matthew.Hennessy/pubs/old/HMjacm85.pdf Algebraic Laws for Nondeterminism and Concurrency], Matthew Hennessy and Robin Milner (first page).</small><!-- 1985 --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | The primary limitation of FP systems is that they are not history sensitive. Therefore they must be extended somehow before they can become [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.628.7053&rep=rep1&type=pdf practically] useful. |
||
+ | But there is an important prerequisite that needs to be observed when attempting to use such models: |
||
− | <tt>[https://www.cs.cmu.edu/~crary/819-f09/Backus78.pdf Can Programming Be Liberated from the von Neumann Style? A Functional Style and Its Algebra of Programs], John Backus (page 11 of 29).</tt> |
||
− | </div> |
||
− | <sup> </sup> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | How must interactions between a program and an external environment (consisting of, e.g., input/output-devices, file systems, ...) be described in a programming language that abstracts from the existence of an outside world? |
||
+ | <blockquote> |
||
− | <tt>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.95.9846&rep=rep1&type=pdf Functions, Frames and Interactions], Claus Reinke (page 10 of 210).</tt> |
||
+ | [...] if either the mathematics or the logic is to have any relevance, a link must be made |
||
− | </div> |
||
+ | between the denotational model and the behavior, or operational semantics, of the |
||
− | <sup> </sup> |
||
+ | programs. |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | Input/output is [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.13.9123&rep=rep1&type=pdf awkward] in declarative languages. Some functional languages like LISP have procedural read and write operations. Prolog has ugly read and write "predicates" that execute in sequence. Haskell monads provide pure functional I/O but still involve a sequence of actions. |
||
+ | So while only having an operational semantics for <code>IO a</code> might |
||
− | <tt>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.227.6709&rep=rep1&type=pdf Specifying Input/Output by Enumeration], Walter W. Wilson and Yu Lei.</tt> |
||
+ | [http://conal.net/blog/posts/is-haskell-a-purely-functional-language#comment-625 not] |
||
− | </div> |
||
+ | be ideal, |
||
+ | [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.13.9123&rep=rep1&type=pdf only having a denotational model]: |
||
+ | <blockquote> |
||
− | It should then be of little surprise that attempts to find a <i>"mathematical solution"</i> for I/O have been less than successful: |
||
+ | <small>(page 19 of 60)</small> |
||
+ | <haskell> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | type IO a = World -> (a, World) |
||
− | Researchers began to analyze why it is often harder to prove things about programs written in traditional languages than it is to prove theorems about mathematics. Two aspects of traditional languages emerged as sources of trouble because they are <b>very difficult to model in a mathematical system</b>: mutability and sequencing. |
||
+ | </haskell> |
||
+ | <haskell> |
||
− | <tt> [https://core.ac.uk/download/pdf/214330064.pdf The Anatomy of Programming Languages], Alice E. Fischer and Frances S. Grodzinsky (emphasis added).</tt> |
||
+ | type IO a = (a, Set Trace) |
||
− | </div> |
||
+ | type Trace = [Event] |
||
+ | data Event = PutChar Char | GetChar Char | ... |
||
+ | </haskell> |
||
+ | </blockquote> |
||
+ | ...would be <i>insufficient:</i> |
||
− | * What would be ideal is an extension of one or more fields of mathematics which can [https://www.cs.kent.ac.uk/people/staff/dat/krc/paraffins-turner.pdf elegantly] describe interactions with external environments - the appropriate denotational semantics can then be used to map it into languages like Haskell. |
||
+ | <blockquote> |
||
− | * Alternately (and less ideally), if it can be proven that one cannot exist (like the solution to the halting problem) then implementors everywhere can just select the most-suitable model of I/O, as they see fit. |
||
+ | It is all very well to aim for a more "abstract" and a |
||
+ | "cleaner" approach to semantics, but if the plan is to be any |
||
+ | good, the operational aspects cannot be completely ignored. The |
||
+ | reason is obvious: in the end the program still must be run on a |
||
+ | machine - a machine which does not possess the benefit of |
||
+ | "abstract" human understanding, a machine that must operate with |
||
+ | finite configurations. |
||
+ | :<small>[https://www.cs.ox.ac.uk/files/3222/PRG02.pdf Outline of a Mathematical Theory of Computation], Dana Scott (page 8 of 30).</small><!-- 1970 --> |
||
− | == An axiomatic approach == |
||
+ | </blockquote> |
||
+ | <blockquote> |
||
− | The dependently-typed language Agda relies on Haskell for its outside interactions: |
||
+ | [...] The meaning of a conventional computer program, as far as |
||
+ | a user is concerned, is just the mathematical function it evaluates. But we users |
||
+ | are <i>inside</i> our interactive systems; we care about what continually goes on. The |
||
+ | meaning surely lies in the whole conversation, not just its end-result. (Indeed there |
||
+ | may be no end-result, since there may have been no goal.) |
||
+ | :<small>[https://perso.ens-lyon.fr/daniel.hirschkoff/dea/papers/milner-infomatics.pdf Turing, Computing and Communication], Robin Milner (page 8 of 12).</small><!-- 1997 --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | '''4 Compiling Agda programs''' |
||
+ | == The procedural boundary == |
||
− | This section deals with the topic of getting Agda programs to interact |
||
− | with the real world. Type checking Agda programs requires evaluating |
||
− | arbitrary terms, ans as long as all terms are pure and normalizing this is |
||
− | not a problem, but what happens when we introduce side effects? Clearly, |
||
− | we don't want side effects to happen at compile time. Another question is |
||
− | what primitives the language should provide for constructing side effecing |
||
− | programs. In Agda, these problems are solved by <i>allowing arbitrary |
||
− | Haskell functions to be imported as axioms.</i> At compile time, these imported |
||
− | functions have no reduction behaviour, <i>only at run time is the |
||
− | Haskell function executed</i>. |
||
+ | In theory, a procedure could be given one or more input registers as arguments and write the result directly to an output register. So if the contents of the input registers change while the procedure is running, its eventual result could be based on some combination of old and new input data. This, <i>while possibly annoying</i>, is to be expected: procedures are allowed to provide different results for the same arguments. |
||
− | <tt>[http://www.cse.chalmers.se/~ulfn/papers/afp08/tutorial.pdf Dependently Typed Programming in Agda], Ulf Norell and James Chapman (<i>emphasis added</i>).</tt> |
||
− | </div> |
||
+ | In practice, one or more procedures <b>are</b> given most, if not all I/O registers along with all available memory addresses. Together with other procedures (and some functions), they form the kernels of most contemporary operating systems. |
||
− | Haskell's FFI also allows for arbitrary foreign code to be imported, to only be executed at run time: |
||
+ | But for a function, such conspicuous variability in its given arguments is untenable: |
||
− | <haskell> |
||
+ | * while a function is being evaluated to obtain a result, |
||
− | instance Monad IO where |
||
+ | * and the result is still being used (it may contain arguments, or be one of them), |
||
− | return = unitIO |
||
+ | the values of its arguments must be kept constant for the result to be correct. |
||
− | (>>=) = bindIO |
||
− | |||
− | foreign import ccall "primUnitIO" unitIO :: a -> IO a |
||
− | foreign import ccall "primBindIO" bindIO :: IO a -> (a -> IO b) -> IO b |
||
− | ⋮ |
||
− | </haskell> |
||
+ | This requirement presents serious difficulties for the direct use of I/O registers with functions: |
||
− | However, Haskell 2010 doesn't allow higher-order FFI declarations, or their use of type variables. It is possible to devise simpler interfaces which can then be used to implement monadic I/O, but Haskell 2010 also imposes restrictions on its I/O type: |
||
+ | * evaluation of a function can take an arbitrarily-long time to complete, |
||
+ | * and providing the result to an external entity could also be slow to finish (the result could be large). |
||
+ | In essence, if a function were to use I/O registers directly, they would have to behave like memory addresses. But that is contrary to the intended purpose of I/O registers! Therefore it is usually easier for the exchange of data between programs and I/O registers to be managed by procedures (or actions in [[House]]), with most other work being done by functions. |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | The <code>IO</code> type serves as a tag for operations (actions) that interact with the outside world. The <code>IO</code> type is abstract: no constructors are visible to the user. |
||
+ | == Seeking freedom == |
||
− | <tt>[https://www.haskell.org/definition/haskell2010.pdf The Haskell 2010 Report] (page 95 of 329).</tt> |
||
− | </div> |
||
+ | It has been proclaimed that: |
||
− | == On being denotative == |
||
+ | <blockquote> |
||
− | Instead of just being declarative, there have been calls for languages like Haskell to be [[Denotative|denotative]]: |
||
+ | The monad constructor <code>IO</code> is a liberation |
||
+ | to the purist functional programmer in that |
||
+ | it permits expression of arbitrary imperative |
||
+ | commands within a higher-order type-secure |
||
+ | language. |
||
+ | :<small>[https://web.archive.org/web/20080325064317/http://www-fp.dcs.st-and.ac.uk/~kh/papers/io-tutorial/section3_2.html#SECTION0002000000000000000 Monadic I/O in Haskell 1.3], Andrew D. Gordon and Kevin Hammond.</small><!-- 1996 --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | My vision of “solving the I/O problem” for functional programming is nothing like Haskell’s semantically imperative (non-)solution (called <code>IO</code> in Haskell), but rather to continue shifting semantically imperative mechanisms out of the programming model and into the implementation of (semantically simple) function application. |
||
+ | But Haskell implementations are written, partly or completely, in another I/O-capable programming language. So if it's already in those implementations, does I/O <i>also</i> have to be present in Haskell? |
||
− | <tt>[http://conal.net/blog/posts/can-functional-programming-be-liberated-from-the-von-neumann-paradigm Conal Elliott.]</tt> |
||
− | </div> |
||
+ | <blockquote> |
||
− | because of how various other effects have already been moved out of languages and into their implementations: |
||
+ | Instead of putting I/O into the functional programming model (as in continuation- and stream-based I/O), or adopting a hybrid functional/imperative model (as in monadic I/O), let’s explore how to move I/O entirely out of our programming model into the implementation of a denotationally simple model for whole systems. |
||
+ | :<small>[http://conal.net/blog/posts/can-functional-programming-be-liberated-from-the-von-neumann-paradigm Can functional programming be liberated from the von Neumann paradigm?], Conal Elliott.</small><!-- 2010 --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | [...] Underneath the implementation of our current functional abstractions (numbers, strings, trees, functions, etc), there are imperative mechanisms, such as memory allocation & deallocation, stack frame modification, and thunk overwriting (to implement laziness). [...] |
||
+ | Variations of this arrangement have been used in the designs of some early functional languages: |
||
− | Stack and register munging and jump/<code>GOTO</code> are implementations of the semantically simpler notion of function application. (I mean “function” in the sense of math and of pure functional programming.) Moreover, stack & register munging is the input/output (IO) part of the implementation of function application. Information goes <b>out</b> of one context and <b>in</b>to another. |
||
− | </div> |
||
+ | <blockquote> |
||
− | There is an assumption here: |
||
+ | One way to deal with this is the so called <u>standard</u> <u>solution</u> The purely |
||
− | * I/O is just another <i>"imperative mechanism"</i>, no different from the rest, therefore it can be similarly sequestered (after all, they do ultimately rely on the same fetch and store operations provided by the solid-state Turing machine running the program). |
||
+ | functional reduction machine is attached to a von Neumann host machine and an |
||
+ | imperative environment deals with I/O and interactive programs. |
||
+ | :<small>[https://repository.ubn.ru.nl/bitstream/handle/2066/17283/1/13352.pdf Functional programming and the language TALE], Henk Barendregt and Marc van Leeuwen (page 6 of 88).</small><!-- 1986 --> |
||
− | ...which is false: |
||
+ | </blockquote> |
||
− | * unlike those other memory-based mechanisms, the simplest of I/O is <b>device-based</b> and the exceedingly-vast majority of I/O devices do not behave like memory. |
||
+ | <blockquote> |
||
− | But the historical precedent is compelling, and I/O may yet be confined to the implementation - it just requires a technique different to the ones used to relocate those other mechanisms: |
||
+ | Another idea is to embed the functional language in an imperative one, which |
||
+ | performs all input and output operations. |
||
+ | :<small>[https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-81.pdf The implementation of functional languages using custom hardware], William Stoye (page 80 of 142).</small><!-- 1985 --> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | </blockquote> |
||
− | [...] we will someday really learn to look at [https://www.cs.columbia.edu/~hgs/internet/definition.html whole systems] in a consistently functional/denotational style (simple & precise semantics). [...] |
||
− | </div> |
||
+ | However: |
||
− | [http://conal.net/blog/posts/can-functional-programming-be-liberated-from-the-von-neumann-paradigm#comment-598 As for the existence of] such a technique: |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | The disadvantage of this approach is |
||
− | [...] I don’t care whether you’re playing “Yes, we can” or “No, we can’t”, so long as you’re rigorous. Rigorous proofs of possibility are usually (not always) constructive: demonstrate an example. That demonstration is what I’m working toward and inviting [[Denotative_programming_timeline|others]] along, as in this post and most of my other work. |
||
+ | that in many cases it results in a substantial fraction of the total programming |
||
− | </div> |
||
+ | effort being expended on developing code in the imperative language. If |
||
+ | functional languages are the best tool for writing programs, then this should be |
||
+ | regarded as a defeat (if they're not, none of this is important). Thus, we must |
||
+ | experiment with extending functional programming techniques to cover |
||
+ | interaction and control operations as much as possible. |
||
+ | </blockquote> |
||
+ | There have been other problems: |
||
− | Presumably the efforts to find that <i>"rigorous proof"</i> (for or against) are ongoing. Until then, the most prudent option is to use the model of I/O which is the least disruptive for languages like Haskell, and not just syntactically or semantically: |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | [...] designers [of Algol 60] felt that input and |
||
− | Unfortunately, a monadic programming style typically differs fundamentally from an ordinary functional style. While this is not as much of a problem if the programming task at hand is side-effecting by nature, it becomes an issue when side effects are only involved peripherally: then, a programmer will be keen to maintain a functional look and feel to the program and not have encapsulation of side effects dominate the overall style of the program. |
||
+ | output were too machine-dependent to be made part of the definition of a universal |
||
+ | language; as a result, the original language definition did not include any input or output |
||
+ | construct, which led every compiler writer to design his own – not a very pleasant |
||
+ | situation for users concerned with portability. (Later versions of Algol 60 defined a |
||
+ | standard mechanism.) |
||
+ | :<small>[https://bertrandmeyer.com/ITPL Introduction to the Theory of Programming Languages], Bertrand Meyer (page 214 of 459).</small><!-- 1991 --> |
||
− | <tt>[https://web.archive.org/web/20200930035115/https://www.holdermans.nl/pubs/assets/hage08heap.pdf Heap Recycling for Lazy Languages], Jurriaan Hage and Stefan Holdermans.</tt> |
||
− | </ |
+ | </blockquote> |
+ | As a result: |
||
− | === Using more than one language === |
||
+ | <blockquote> |
||
− | One suggestion is to ease the relocation of effects into the implementation by using a suitable imperative language: |
||
+ | More recent designs such as C, Ada and Eiffel keep input-output |
||
+ | mechanisms out of the language, in the Algol tradition, but do not shirk their |
||
+ | responsibilities since they define one or more standard input-output libraries. |
||
+ | </blockquote> |
||
+ | === A historical note === |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | My view is that the next logical step for programming is to split into two non-overlapping programming domains: |
||
+ | The stream-based (or dialogue) I/O model provided in Haskell prior to version 1.3 required substantial support from implementations e.g. by using an imperative “wrapper”: |
||
− | * runtime building for ... |
||
− | * ... mathematical programming languages |
||
+ | <blockquote> |
||
− | [...] Haskell is one example of a programming language where the code aspires to resemble pure mathematical expressions and definitions. |
||
+ | It repeatedly takes a request off the result list, acts on |
||
+ | the request, and attaches an appropriate response to the argument list. There has be some clever |
||
+ | footwork to deal with the fact that the function has to be applied to a list of responses before |
||
+ | there <i>are</i> any responses in the list, but that isn’t a problem in a lazy setting. |
||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.13.9123&rep=rep1&type=pdf Tackling the Awkward Squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell], Simon Peyton Jones (pages 4-5 of 60).</small><!-- 2001 --> |
||
− | <tt>[https://www.haskellforall.com/2021/04/the-end-of-history-for-programming.html Gabriella Gonzalez].</tt> |
||
− | </ |
+ | </blockquote> |
+ | So why was it replaced? |
||
− | So instead of having the denotative/imperative division within Haskell [https://dl.acm.org/doi/pdf/10.1145/319838.319848 by way of types], it would be at the language level in the forms of differing syntax and semantics, foreign calls, and so forth. This too could be alleviated by keeping both languages as similar as possible, but if this is taken to its logical conclusion then the only difference between the denotative and implementation languages would be just the imperative features, which would make having two such similar languages effectively redundant: |
||
+ | <blockquote> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
+ | [...] it has several defects: |
||
− | [...] It merely delays the issue of how one is to communicate with a persistent outside world. Sooner or later the question of interfacing to [networks], remote filing systems and other computers must be faced. |
||
+ | * It is hard to extend. New input or output facilities can be added only by extending the <code>Request</code> and <code>Response</code> types, and by changing the “wrapper” program. Ordinary users are unlikely to be able to do this. |
||
− | <tt>[https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-56.pdf A New Scheme for Writing Functional Operating Systems], William Stoye (page 18 of 31).</tt> |
||
− | </div> |
||
− | <sup> </sup> |
||
− | <div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"> |
||
− | [...] Proving correctness is a formal activity. Therefore we must be able to lift an arbitrary implementation to the formal level. In order not to be forced to specify all details of an implementation, we have to admit nondeterminism on the formal level. It is especially useful in treating things like memory allocation, overflow conditions, and uninitialized fields of structured values [as well as [[Concurrency|concurrency]]]. |
||
+ | * There is no very close connection between a request and its corresponding response. It is extremely easy to write a program that gets one or more “out of step”. |
||
− | The leading principle is to avoid premature or unnecessary design decisions. Therefore we have a preference for loose specifications, which admit a variety of nonisomorphic models. [...] |
||
+ | * Even if the program remains in step, it is easy to accidentally evaluate the response stream too eagerly, and thereby block emitting a request until the response to that request has arrived – which it won’t. |
||
− | <tt>[https://dl.acm.org/doi/pdf/10.1145/42192.42194 A Mathematical Approach to Nondeterminism in Data Types], Wim H. Hesselink.</tt> |
||
− | </ |
+ | </blockquote> |
+ | |||
+ | The monadic interface helped to shift the first problem - the difficulty of extending - out of those early Haskell implementations: |
||
+ | |||
+ | <blockquote> |
||
+ | * <i>It is easily extensible</i>. The key to our implementation is to extend Haskell with a single form that allows one to call an any procedure written in the programming language C [https://archive.org/details/cprogramminglang00kern <span></span>], without losing referential transparency (Section 2.3). Using it programmers can readily extend the power of the I/O system, by writing Haskell functions which call operating system procedures. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.9725&rep=rep1&type=pdf Imperative functional programming] Simon Peyton Jones and Philip Wadler (first page).</small><!-- 1993 --> |
||
+ | </blockquote> |
||
+ | |||
+ | This made it possible to define dialogue I/O, “wrapper” and all, in Haskell: |
||
+ | |||
+ | <blockquote> |
||
+ | The entire I/O system provided by our compiler |
||
+ | is written in Haskell, using the non-standard extensions |
||
+ | we describe below. The language’s standard <code>Dialogue</code> |
||
+ | interface for I/O is supported by providing a function to |
||
+ | convert a <code>Dialogue</code> into our <code>IO</code> monad. |
||
+ | |||
+ | :<small>(second page).</small> |
||
+ | </blockquote> |
||
+ | |||
+ | Any proposal which involves shifting I/O <i>back</i> into modern Haskell implementations must therefore have a practical solution to that original problem - the difficulty of extending implementations. |
||
== Open questions == |
== Open questions == |
||
Line 414: | Line 497: | ||
::[https://chadaustin.me/2015/09/haskell-is-not-a-purely-functional-language Haskell is not a purely functional language], but is often described as being referentially transparent. |
::[https://chadaustin.me/2015/09/haskell-is-not-a-purely-functional-language Haskell is not a purely functional language], but is often described as being referentially transparent. |
||
− | |||
− | * Can functional programming be liberated from the von Neumann paradigm? |
||
− | |||
− | ::Only if no-one proves it to be impossible (e.g. like trying to solve the halting problem). |
||
* Why do our programs need to read input and write output? |
* Why do our programs need to read input and write output? |
||
Line 424: | Line 503: | ||
== Other articles == |
== Other articles == |
||
+ | |||
+ | * [https://aitopics.org/download/classics:4A93472A LOGLISP: an alternative to PROLOG], John A. Robinson and Ernest E. Sibert. <!-- 1982 --> |
||
+ | |||
+ | * [https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-56.pdf A New Scheme for Writing Functional Operating Systems], William Stoye. <!-- 1984 --> |
||
* [https://core.ac.uk/download/pdf/82162724.pdf Functional Programming with Side Effects], Mark B. Josephs. <!-- 1986 --> |
* [https://core.ac.uk/download/pdf/82162724.pdf Functional Programming with Side Effects], Mark B. Josephs. <!-- 1986 --> |
||
Line 429: | Line 512: | ||
* [https://www.cs.unc.edu/techreports/88-022.pdf The Semantics of an FP Language with Infinite Objects], Teresa Thomas. <!-- 1988 --> |
* [https://www.cs.unc.edu/techreports/88-022.pdf The Semantics of an FP Language with Infinite Objects], Teresa Thomas. <!-- 1988 --> |
||
− | * [https:// |
+ | * [https://dl.acm.org/doi/pdf/10.1145/42192.42194 A Mathematical Approach to Nondeterminism in Data Types], Wim H. Hesselink. <!-- 1988 --> |
* [https://www.cs.bham.ac.uk/~udr/papers/assign.pdf Assignments for Applicative Languages], Vipin Swarup, Uday S. Reddy and Evan Ireland. <!-- 1991 --> |
* [https://www.cs.bham.ac.uk/~udr/papers/assign.pdf Assignments for Applicative Languages], Vipin Swarup, Uday S. Reddy and Evan Ireland. <!-- 1991 --> |
||
+ | |||
+ | * [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.50.6183&rep=rep1&type=pdf TIP in Haskell – Another Exercise in Functional Programming], Colin Runciman. <!-- 1991 --> |
||
+ | |||
+ | * [https://vtechworks.lib.vt.edu/server/api/core/bitstreams/17d5c727-8c8b-4433-b7d0-f9f4e1be20e9/content A Functional Approach to Graphics Programming and Modeling], S. Ramakrishnan. <!-- 1992 --> |
||
* [https://www.cs.bham.ac.uk/~udr/papers/imperative-functional.pdf Imperative Functional Programming], Uday S. Reddy. <!-- 1996 --> |
* [https://www.cs.bham.ac.uk/~udr/papers/imperative-functional.pdf Imperative Functional Programming], Uday S. Reddy. <!-- 1996 --> |
||
− | * [https://core.ac.uk/download/pdf/ |
+ | * [https://core.ac.uk/download/pdf/81924021.pdf A representable approach to finite nondeterminism], S. O. Anderson and A. J. Power. <!-- 1997 --> |
+ | * [https://web.archive.org/web/20151217222912/https://haskell.cs.yale.edu/wp-content/uploads/2011/02/es01.pdf Directions in Functional Programming for Real(-Time) Applications], Walid Taha, Paul Hudak and Zhanyong Wan. <!-- 2001--> |
||
− | * [https://maartenfokkinga.github.io/utwente/mmf2001c.pdf An alternative approach to I/O], Maarten Fokkinga and Jan Kuper. <!-- 2001 --> |
||
* [https://www.diva-portal.org/smash/get/diva2:1000395/FULLTEXT01.pdf Reactive Objects], Johan Nordlander, Mark P. Jones, Magnus Carlsson, Richard B. Kieburtz, and Andrew Black. <!-- 2002 --> |
* [https://www.diva-portal.org/smash/get/diva2:1000395/FULLTEXT01.pdf Reactive Objects], Johan Nordlander, Mark P. Jones, Magnus Carlsson, Richard B. Kieburtz, and Andrew Black. <!-- 2002 --> |
||
+ | |||
+ | * [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.167.3926&rep=rep1&type=pdf Can GUI Programming Be Liberated From The IO Monad], John Peterson, Antony Courtney and Henrik Nilsson. <!-- 2005 --> |
||
* [https://www.f.waseda.jp/terauchi/papers/toplas-witness.pdf Witnessing Side Effects], Tachio Terauchi and Alex Aiken. <!-- 2006 --> |
* [https://www.f.waseda.jp/terauchi/papers/toplas-witness.pdf Witnessing Side Effects], Tachio Terauchi and Alex Aiken. <!-- 2006 --> |
||
Line 445: | Line 534: | ||
* [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.95.7225&rep=rep1&type=pdf Programming Languages For Interactive Computing], Roly Perera. <!-- 2007 --> |
* [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.95.7225&rep=rep1&type=pdf Programming Languages For Interactive Computing], Roly Perera. <!-- 2007 --> |
||
+ | * [https://web.archive.org/web/20200930035115/https://www.holdermans.nl/pubs/assets/hage08heap.pdf Heap Recycling for Lazy Languages], Jurriaan Hage and Stefan Holdermans. <!-- 2008 --> |
||
− | * [https://www.researchgate.net/profile/Clemens-Grelck/publication/220997216_Controlling_chaos_on_safe_side-effects_in_data-parallel_operations/links/543bb4670cf2d6698be31618/Controlling-chaos-on-safe-side-effects-in-data-parallel-operations.pdf Controlling Chaos: On Safe Side-Effects in Data-Parallel Operations], Stephan Herhut, Sven-Bodo Scholz and Clemens Grelck. <!-- 2009 --> |
||
+ | |||
+ | * [https://www2.ccs.neu.edu/racket/pubs/icfp09-fffk.pdf A Functional I/O System], Matthias Felleisen, Robert Bruce Findler, Matthew Flatt and Shriram Krishnamurthi. <!-- 2009 --> |
||
+ | |||
+ | * [https://www.sac-home.org/_media/publications:pdf:2012_1.pdf Single Assignment C (SAC): High Productivity Meets High Performance], Clemens Grelck. <!-- 2012 --> |
||
+ | |||
+ | * [https://www.usenix.org/system/files/1311_05-08_mickens.pdf The Night Watch], James Mickens. <!-- 2013 --> |
||
+ | |||
+ | * [https://cs-people.bu.edu/gaboardi/publication/GaboardiEtAlIicfp16.pdf Combining Effects and Coeffects via Grading], Marco Gaboardi, Flavien Breuvart, Shin-ya Katsumata, Dominic Orchard and Tarmo Uustalu. <!-- 2016 --> |
||
+ | |||
+ | * [https://plus.maths.org/content/category/tags/mathematical-mysteries Mathematical mysteries], <i>Plus</i> magazine. |
||
+ | |||
+ | === More quotes === |
||
+ | ---- |
||
+ | <b>1978</b> |
||
+ | <blockquote> |
||
+ | The primary limitation of FP systems is that they are |
||
+ | not history sensitive. Therefore they must be extended |
||
+ | somehow before they can become practically useful. |
||
+ | |||
+ | :<small>[https://www.cs.cmu.edu/~crary/819-f09/Backus78.pdf Can Programming Be Liberated from the von Neumann Style? A Functional Style and Its Algebra of Programs], John Backus (page 11 of 29).</small><!-- 1978 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1980</b> |
||
+ | <blockquote> |
||
+ | An other important point is that FP systems [...] have no means to save |
||
+ | definitions or results produced by a computation and to recall them later. Therefore, they must be imbedded |
||
+ | into an environment capable of performing these tasks for them. |
||
+ | |||
+ | :<small>[https://dl.acm.org/doi/pdf/10.1145/800176.809975 FAD, a Functional Programming Language that Supports Abstract Data Types], Johannes J. Martin (page 2 of 16).</small><!-- 1980 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1984</b> |
||
+ | <blockquote> |
||
+ | [...‘stream-processing’ solutions based on] systems of |
||
+ | communicating processes can be described in a purely functional language by recursion over |
||
+ | infinite lists; this is important because it open up the way for problems involving input–output |
||
+ | and communication to be dealt with cleanly within the functional style [[https://eighty-twenty.org/files/Henderson%20-%201982%20-%20Purely%20Functional%20Operating%20Systems.pdf <span></span>]]. |
||
+ | |||
+ | :<small>[https://www.researchgate.net/profile/B-Wichmann/publication/243687527_Functional_Programs_as_Executable_Specifications_Discussion/links/5693913908aee91f69a836d7/Functional-Programs-as-Executable-Specifications-Discussion.pdf Functional Programs as Executable Specifications: Discussion], David A. Turner (page 17 of 27).</small><!-- 1984 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1986</b> |
||
+ | <blockquote> |
||
+ | Functional languages are extremely powerful and succinct tools for expressing |
||
+ | algorithms[https://www.cambridge.org/9780521245036 <span></span>], |
||
+ | but the way in which the results of such calculations should be |
||
+ | communicated to the outside world is not obvious. |
||
+ | |||
+ | :<small>[https://core.ac.uk/download/pdf/82449736.pdf Message-based functional operating systems], William Stoye (first page).</small><!-- 1986 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Input and output are perhaps the most systematically |
||
+ | neglected features of programming languages. They are |
||
+ | usually ad hoc, and they are usually poorly integrated |
||
+ | with the other facilities of their hosts – the languages in |
||
+ | which they are embedded. |
||
+ | |||
+ | :<small>[https://dl.acm.org/doi/pdf/10.1145/22627.22382 An Input-Output Model for Interactive Systems], Mary Shaw (first page).</small><!-- 1986 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1987</b> |
||
+ | <blockquote> |
||
+ | The utility of the different programming style imposed by restricting side-effects is debatable, but it |
||
+ | is fair to say that operations such as input and output (since they are history sensitive — i.e. they are |
||
+ | inherently side-effects) are particularly awkward to express. |
||
+ | |||
+ | :<small>[http://aggregate.org/REFINED/thesis.pdf The Refined-Language Approach To Compiling For Parallel Supercomputers], Henry G. Dietz (page 34 of 188).</small><!-- 1987 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1989</b> |
||
+ | <blockquote> |
||
+ | Is there any hope of achieving <i>purely functional</i>, yet <i>universal</i>, and of course |
||
+ | <i>efficient</i> I/O? |
||
+ | |||
+ | :<small>[https://web.archive.org/web/20210615132250/https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.49.695&rep=rep1&type=pdf On the Expressiveness of Purely Functional I/O Systems], Paul Hudak and Raman S. Sundaresh (page 2 of 29).</small><!-- 1989 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | It is not clear how one might express an interactive process as a function — this is |
||
+ | still a research topic, see for example [https://www.cs.kent.ac.uk/pubs/1987/142/content.pdf Interactive functional programs: a method and a formal semantics]. |
||
+ | |||
+ | :<small>[https://kar.kent.ac.uk/94289/1/257007.pdf The design and implementation of an operating system in a functional language], John R. G. Cupitt (page 10 of 150).</small><!-- 1989 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Starting with Landin streams many I/O schemes have been proposed for purely functional |
||
+ | languages, but they tend to be <i>ad hoc</i> in the sense of being designed to express |
||
+ | particular kinds of I/O, without aiming for universal power. |
||
+ | |||
+ | :<small>[https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-160.pdf PFL+: a kernel scheme for functional I/O], Andrew Gordon (page 4 of 28).</small><!-- 1989 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | A straightforward |
||
+ | example of such a problematical application is that of a |
||
+ | function which could allow us to interactively query and |
||
+ | modify a database; this is clearly an interactive problem, |
||
+ | since we may only be able to formulate queries once we |
||
+ | have seen the responses to earlier ones. |
||
+ | |||
+ | :<small>[https://academic.oup.com/comjnl/article-pdf/32/2/162/1445725/320162.pdf Functional Programming and Operating Systems], Simon B. Jones and A. F. Sinclair (first page).</small><!-- 1989 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | At present most declarative languages are guest |
||
+ | languages on [...] procedural machines, and able to preserve their |
||
+ | data in the file system provided by the host machine. However, the interface |
||
+ | to the file system that is provided by the guest languages is primitive |
||
+ | and often not referentially transparent. |
||
+ | |||
+ | :<small>[https://www.cs.ox.ac.uk/files/3404/PRG82.pdf A Functional Database], Phil Trinder (page 14 of 210).</small><!-- 1989 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1990</b> |
||
+ | <blockquote> |
||
+ | A functional program transforms data into other data according to a certain |
||
+ | algorithm. Functional programs cannot deal with input/output, cannot switch on and |
||
+ | off lamps depending on the value of a certain parameter; in general they cannot deal |
||
+ | with <i>process control</i>. |
||
+ | |||
+ | :<small>[https://repository.ubn.ru.nl/bitstream/handle/2066/17230/13246.pdf Functional Programming and Lambda Calculus], Henk Barendregt (page 324).</small><!-- 1990 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | To maintain correct I/O behaviour the relative temporal ordering of individual I/O operations must be controlled. |
||
+ | [...] However, in pure functional languages, as they are referentially transparent, there is usually no |
||
+ | mechanism to control the temporal ordering of the evaluation, hence maintaining correct I/O behaviour is |
||
+ | non-trivial<sup>3</sup>. [...] |
||
+ | |||
+ | <sup>3</sup>It is non-trival as a programmer needs always to be considering <i>how</i> something will be executed – which |
||
+ | is only possible with a thorough understanding of the evaluation strategy/denotational semantics. It is also a |
||
+ | task from which functional programming is usually claimed to relieve the programmer. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.628.7053&rep=rep1&type=pdf The implementation of practical functional programming languages], Nigel Perry (page 18 of 144).</small><!-- 1990 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1991</b> |
||
+ | <blockquote> |
||
+ | Input and output do not require justification: a program without communication with the |
||
+ | outside world is of little use. |
||
+ | |||
+ | :<small>[https://bertrandmeyer.com/ITPL Introduction to the Theory of Programming Languages], Bertrand Meyer (page 214 of 459).</small><!-- 1991 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1992</b> |
||
+ | <blockquote> |
||
+ | One consequence of referential transparency is |
||
+ | that it is difficult to incorporate I/O into a pure |
||
+ | functional language. [...] Alternative models have been |
||
+ | proposed which do not suffer from this difficulty; see |
||
+ | for example the Haskell [version 1.1] report[https://www.haskell.org/definition </span></span>], |
||
+ | which attempts to represent the current consensus in the |
||
+ | field. Nonetheless, these other models are notationally |
||
+ | complex, and I/O modeling remains a problem. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.54.8751&rep=rep1&type=pdf Using a Lazy Functional Language for Textual Information Retrieval], Donald Ziff, Keith Waclena, and Stephen Spackman (page 3 of 13).</small><!-- 1992 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | A lot has been said in favour of functional programming |
||
+ | [https://www.cs.cmu.edu/~crary/819-f09/Backus78.pdf <span></span>] |
||
+ | [https://www.cse.chalmers.se/~rjmh/Papers/whyfp.pdf <span></span>] |
||
+ | but the fact is |
||
+ | that functional programming suffers from a paramount lack of appreciation in |
||
+ | the established programming society. For one reason this is caused by the fact |
||
+ | that only recently functional programs have gained execution speeds comparable |
||
+ | to their imperative rivals |
||
+ | [https://repository.ubn.ru.nl/bitstream/handle/2066/107649/1/107649.pdf <span></span>] |
||
+ | [http://www.mbsd.cs.ru.nl/publications/papers/1991/smes91-codegeneration.ps.gz <span></span>] |
||
+ | [https://www.mbsd.cs.ru.nl/publications/papers/1991/groj91-HeapManABCMach.pdf <span></span>]. |
||
+ | Another important reason is that functional |
||
+ | programming defected on performing input output (I/O hereafter) with the |
||
+ | outer world. |
||
+ | |||
+ | I/O and functional programming doesn’t seem to be unifiable: functional |
||
+ | languages don’t have the notion of <i>side-effects</i> and lack a precise <i>control of the |
||
+ | evaluation order</i>. These are precisely the important aspects for any I/O model. |
||
+ | There have been many proposals how to deal with I/O (see section 8) but none |
||
+ | of them are completely satisfactory. In particular it is very hard to deal with the |
||
+ | side-effect problem. |
||
+ | |||
+ | :<small>[https://www.mbsd.cs.ru.nl/publications/papers/1992/achp92-HighLevelIO.pdf High Level Specification of I/O in Functional Languages], Peter Achten, John van Groningen, Rinus Plasmeijer (pages 1-2 of 17).</small><!-- 1992 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1993</b> |
||
+ | <blockquote> |
||
+ | In the case of input/output, which typically takes the form of an ordered sequence of events, it |
||
+ | has always been hard to deny convincingly that the imperative model is more intuitive. Functional |
||
+ | models using streams or continuations have always been difficult to grasp at first, whereas practically |
||
+ | anyone can quickly come to terms with the ‘input <i>a</i>; print <i>a</i>’ nature of basic (or BASIC) imperative |
||
+ | languages. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.52.2795&rep=rep1&type=pdf Animating Z specifications in Haskell using a monad], Howard S. Goodman (page 25 of 31).</small><!-- 1993 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | A disadvantage of the [stream] method for writing interactive functional |
||
+ | programs is that every part of the output has to be part of the result |
||
+ | of the whole program on the top level. As a consequence it is not a |
||
+ | trivial task to change a program in such a way that for a specific function |
||
+ | that is used somewhere in an expression the value of its arguments |
||
+ | is printed every time the function is called. A change like that, which |
||
+ | can be of interest for tracing or debugging, requires a change of the |
||
+ | structure of the whole program. |
||
+ | |||
+ | :<small>[https://www.researchgate.net/profile/Marko-Eekelen/publication/220688529_Functional_Programming_and_Parallel_Graph_Rewriting/links/00b4952af4a04d487b000000/Functional-Programming-and-Parallel-Graph-Rewriting.pdf Functional Programming and Parallel Graph Rewriting], Rinus Plasmeijer and Marko van Eekelen (page 82 of 623).</small><!-- 1993 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1994</b> |
||
+ | <blockquote> |
||
+ | Although the advantages of functional programming are fairly well known, a few areas have |
||
+ | proved troublesome, I/O being one of these. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.38.2254&rep=rep1&type=pdf Functional Languages and Graphical User Interfaces - a review and a case study], Rob Noble and Colin Runciman (page 6 of 51).</small><!-- 1994 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | There are many attempts to integrate I/O into functional languages, such as linear types |
||
+ | [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.55.5439&rep=rep1&type=pdf <span></span>], and monads |
||
+ | [https://www.research.ed.ac.uk/files/7944776/Comprehending_monads.pdf <span></span>] |
||
+ | [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.41.9361&rep=rep1&type=pdf <span></span>] |
||
+ | in Haskell, or uniqueness typing in Clean |
||
+ | [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.43.6060&rep=rep1&type=pdf <span></span>] |
||
+ | [https://www.researchgate.net/profile/Marko-Eekelen/publication/221024513_Guaranteeing_Safe_Destructive_Updates_Through_a_Type_System_with_Uniqueness_Information_for_Graphs/links/00b7d539eeb0638d07000000/Guaranteeing-Safe-Destructive-Updates-Through-a-Type-System-with-Uniqueness-Information-for-Graphs.pdf <span></span>]. |
||
+ | These approaches have in common that the programmer explicitly has to create |
||
+ | data dependencies among consecutive I/O operations which lead to very awkward notations. |
||
+ | |||
+ | :<small>[https://www.sac-home.org/_media/publications:pdf:sac-overview-norwich-94.pdf Single Assignment C - Functional Programming Using Imperative Style], Sven-Bodo Scholz (page 2 of 13).</small><!-- 1994 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1995</b> |
||
+ | <blockquote> |
||
+ | In pure functional languages, several proposals have been made for clean |
||
+ | I/O models. We mention Landin’s streams[https://dl.acm.org/doi/pdf/10.1145/363744.363749 <span></span>][https://dl.acm.org/doi/pdf/10.1145/363791.363804 <span></span>], |
||
+ | Monads[https://www.cs.cmu.edu/~crary/819-f09/Moggi89.pdf <span></span>][https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.9725&rep=rep1&type=pdf <span></span>], |
||
+ | and Uniqueness Types[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.36.5737&rep=rep1&type=pdf <span></span>]. |
||
+ | Compared to our approach, these models are more deterministic [when less is required], |
||
+ | especially with respect to output. More generally, these models sequentialize |
||
+ | I/O actions by imposing static constraints (usually expressed as types) on the |
||
+ | program. |
||
+ | |||
+ | :<small>[https://www.researchgate.net/profile/Pum-Walters/publication/243782477_A_Model_for_IO_in_Equational_Languages_with_Don't_Care_Nondeterminism/links/59883bbaaca27266ada3f6c3/A-Model-for-I-O-in-Equational-Languages-with-Dont-Care-Nondeterminism.pdf A model for I/O in equational languages with don’t care non-determinism], H. R. Walters and J. F. Th. Kamperman (page 14 of 15).</small><!-- 1995 --> |
||
+ | </blockquote> |
||
+ | <blockquote> |
||
+ | If, however, we wish to classify programs that have potentially |
||
+ | infinite behaviors, such as a program that echoes its input, then a more direct model of |
||
+ | input-output seems necessary. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.44.2950&rep=rep1&type=pdf Untyped Lambda-Calculus with Input-Output], Jerzy Tiuryn and Mitchell Wand (page 2 of 11)</small><!-- 1995 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1996</b> |
||
+ | <blockquote> |
||
+ | The programming style in a lazy functional language is heavily influenced by |
||
+ | the supported I/O-mechanism. Modifying the I/O-behaviour or debugging some |
||
+ | lazy functional program that uses I/O is a black art. It is interesting that novices |
||
+ | in lazy functional programming in general expect that there is some direct |
||
+ | (side-effecting) I/O using a function call. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.55.1076&rep=rep1&type=pdf A Partial Rehabilitation of Side-Effecting I/O:], Manfred Schmidt-Schauß (first page).</small><!-- 1996 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | No formal semantics for these I/O primitives |
||
+ | is possible at present, because there is no |
||
+ | complete formal semantics for Haskell itself. We |
||
+ | hope in future that such a semantics will be |
||
+ | developed. One task of such a semantics would |
||
+ | be to show that the <code>IO</code> type does indeed form a |
||
+ | monad in the categorical sense. |
||
+ | |||
+ | :<small>[https://web.archive.org/web/20080325055637/http://www-fp.dcs.st-and.ac.uk/~kh/papers/io-tutorial/section3_7.html#SECTION0007000000000000000 Monadic I/O in Haskell 1.3], Andrew D. Gordon and Kevin Hammond.</small><!-- 1996 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | For other models of computation like functional or logic programming, |
||
+ | the typical approach has been to add extra features implementing I/O. But |
||
+ | these features do not fit in the nice and simple underlying model: in order |
||
+ | to be able to understand or reason about programs involving I/O, the basic |
||
+ | computational model has to be extended in non trivial ways, making it not so |
||
+ | nice and simple anymore [...] |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.48.2591&rep=rep1&type=pdf Input/Output for ELAN], Patrick Viry (first page).</small><!-- 1996 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1997</b> |
||
+ | <blockquote> |
||
+ | While it is fine that monadic I/O has good theoretical under-pinnings, did anyone |
||
+ | stop to think if it helped in user interface programming? If all that it is is a means <i>somehow</i> |
||
+ | to construct interactive programs, then it succeeds, but that is not enough. A programmer |
||
+ | chooses a language based not on only on ability, but also usability. |
||
+ | |||
+ | :<small>[https://core.ac.uk/download/pdf/293056217.pdf Interacting with Functional Languages], Duncan Sinclair (page 15 of 159).</small><!-- 1997 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1998</b> |
||
+ | <blockquote> |
||
+ | Uniqueness typing addresses the more general problem |
||
+ | of statically controlled use of resources in functional programs and, even if |
||
+ | combined with passing unique representations of environment objects as arguments |
||
+ | to these programs, it does not suffice to solve the input/output-problem. The |
||
+ | reason is that the environment is not updated in one conceptual step <i>after</i> the |
||
+ | evaluation of a program has computed a new environment representation but |
||
+ | rather in small steps <i>whenever</i> the environment representation is modified during |
||
+ | program evaluation. The primitive interactions are thus implemented as |
||
+ | side-effecting operations, the use of which is rendered safe in the |
||
+ | uniqueness-typed environment passing framework. |
||
+ | |||
+ | Similarly, monads are used to address the more general problem of computations |
||
+ | (involving state, input/output, backtracking, ...) returning values: they do |
||
+ | not solve any input/output-problems directly but rather provide an elegant and |
||
+ | flexible abstraction of many solutions to related problems [...]. For instance, |
||
+ | no less than three different input/output-schemes are used to solve these |
||
+ | basic problems in [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.9725&rep=rep1&type=pdf Imperative functional programming], |
||
+ | the paper which originally proposed ‘a new model, based on monads, for |
||
+ | performing input/output in a non-strict, purely functional language’. [...] |
||
+ | |||
+ | So, both input/output-schemes merely provide frameworks in which side-effecting |
||
+ | operations can safely be used with a guaranteed order of execution and |
||
+ | without affecting the properties of the purely functional parts of the language. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.95.9846&rep=rep1&type=pdf Functions, Frames and Interactions], Claus Reinke (pages 96-97 of 210).</small><!-- 1998 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>1999</b> |
||
+ | <blockquote> |
||
+ | Since I/O is by nature side effects, Haskell handles it differently. Monadic I/O is used to overcome this problem. |
||
+ | |||
+ | After overcoming Haskell's I/O, there were no more setbacks in writing the program. |
||
+ | |||
+ | :<small>[https://www.mta.ca/~rrosebru/oldcourse/371199/haskell/paper.htm Functional Programming Using Haskell], Wade Estabrooks, Michael Goit and Mark Steeves.</small><!-- 1999 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Only theorists find it interesting to write programs that don’t require input or produce output. |
||
+ | |||
+ | :<small>[https://archive.org/details/JavaIO-OReilly Java I/O], Elliotte Rusty Harold (page 21 of 479).</small><!-- 1999 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Ever since McCarthy [http://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf <span></span>] |
||
+ | referred to the input/output (I/O) operations <code>READ</code> |
||
+ | and <code>PRINT</code> in LISP 1.5 as "pseudo-functions," I/O effects have been viewed with |
||
+ | suspicion. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.52.6409&rep=rep1&type=pdf Relating Operational and Denotational Semantics for Input/Output Effects], Roy L. Crole and Andrew D. Gordon (page 2 of 38).</small><!-- 1999 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Something fundamental and innocent looking as simple I/O has been a hard |
||
+ | problem for functional languages. Many models, such lazy streams, continuation |
||
+ | semantics, and systems model |
||
+ | [https://cpsc.yale.edu/sites/default/files/files/tr665.pdf <span></span>] |
||
+ | [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.16.3541&rep=rep1&typpe=pdf <span></span>] |
||
+ | [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.134.5784&rep=rep1&type=pdf <span></span>] |
||
+ | have been proposed to overcome the discrepancy between a referential |
||
+ | transparent language and I/O side effects. Hudak gives examples of the above |
||
+ | I/O styles [https://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.83.6505&rep=rep1&type=pdf <span></span>] |
||
+ | and although imperative syntax is mimicked they look |
||
+ | very un-intuitive and cumbersome to someone used to plain I/O statements. |
||
+ | Recently, a step forward has been made by employing so-called monads for |
||
+ | I/O [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.9725&rep=rep1&type=pdf <span></span>] |
||
+ | <!-- Carlsson & Hallgren, 1993-05? -->. This model has also been adopted |
||
+ | for the latest revision for HASKELL [version 98]. It remains a matter of taste whether such a |
||
+ | treatment of I/O state is conceived as natural or unacceptable. |
||
+ | |||
+ | :<small>[https://docs.ahcts.co/how-to-program/fps-sans-escher.pdf A Functional Pattern System for Object-Oriented Design], Thomas Kühne (page 40 of 346).</small><!-- 1999 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2001</b> |
||
+ | <blockquote> |
||
+ | Now that we have discussed the monadic approach in some detail, you may well be asking the |
||
+ | following question: once we have added imperative-looking input/output, concurrency, shared |
||
+ | variables, and exceptions, have we not simply re-invented good old procedural programming? |
||
+ | Have we “lost the plot” [...] |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.13.9123&rep=rep1&type=pdf Tackling the Awkward Squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell], Simon Peyton Jones (page 55 of 60).</small><!-- 2001 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2002</b> |
||
+ | <blockquote> |
||
+ | In our approach, we would suggest to dismantle the <code>IO</code> |
||
+ | monad into its constituting monads, and combine them with the |
||
+ | coproduct as needed. This has the advantage that the effects of most |
||
+ | monads can be localised, so using e.g. state threads or exceptions |
||
+ | in one part of the program will not make the type of every function |
||
+ | using this part monadic, as is currently the case with the <code>IO</code> |
||
+ | monad. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.128.1864&rep=rep1&type=pdf Composing Monads Using Coproducts], Christoph Lüth and Neil Ghani (page 11 of 12).</small><!-- 2002 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2003</b> |
||
+ | <blockquote> |
||
+ | It is possible that a declarative programming style for the IO |
||
+ | part of a program can be integrated into Haskell. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.69.4510&rep=rep1&type=pdf Realising nondeterministic I/O in the Glasgow Haskell Compiler], David Sabel (page 37 of 39).</small><!-- 2003 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | The common method to relieve the programming language designer from the |
||
+ | inherent IO-problems is to shift responsibility to the programmer who has to |
||
+ | sequentialize all IO-requests. This is also true for the monadic approach |
||
+ | implemented in Haskell [version 98] [https://www.haskell.org/onlinereport <span></span>]. |
||
+ | |||
+ | :<small>[https://core.ac.uk/download/pdf/14504553.pdf FUNDIO: A Lambda-Calculus With <i>letrec</i>, <i>case</i>, Constructors, and an IO-Interface:], Manfred Schmidt-Schauß (page 3 of 84).</small><!-- 2003 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2004</b> |
||
+ | <blockquote> |
||
+ | As for intrinsic advantage, I think Haskell has at least one obvious handicap -- monadic I/O. Every minute I spend trying to understand how to program with it is a minute I am solving a problem I don't care about. |
||
+ | |||
+ | :<small>[http://lambda-the-ultimate.org/node/186#comment-1436 New Paul Graham thing], <q>sean</q>.</small><!-- 2004 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2005</b> |
||
+ | <blockquote> |
||
+ | [...] doing IO in Haskell means using a polymorphic type as well as a mathematical theory that is rather obtuse. That's why IO is so far down in this tutorial. |
||
+ | |||
+ | :<small>[https://web.archive.org/web/20160408094723/http://www.kt.rim.or.jp/~kbk/haskell-intro/section3.html#part7 Haskell Tutorial for C Programmers], Eric Etheridge.</small><!-- 2005 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | <tt>HASKELL</tt> uses <i>monads</i> for destructive updates and I/O; they add a |
||
+ | restricted form of stateful computation to a pure language, |
||
+ | retaining referential transparency |
||
+ | [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.91.3579&rep=rep1&type=pdf <span></span>]. |
||
+ | The disadvantage is that programs become more complicated. Also, |
||
+ | if imperative elements of a given application were not |
||
+ | taken into account during its design but turn out to |
||
+ | be necessary later on, often major parts have to be |
||
+ | redesigned or (at least) reimplemented, especially because |
||
+ | types change significantly. [...] |
||
+ | |||
+ | The <tt>TRUTH</tt> team considers this point as one of the |
||
+ | biggest drawbacks of the purely functional paradigm as |
||
+ | followed by <tt>HASKELL</tt>. |
||
+ | |||
+ | :<small>[https://homepages.inf.ed.ac.uk/perdita/haskml.pdf Functional programming languages for verification tools: A comparison of Standard ML and Haskell], Martin Leucker, Thomas Noll, Perdita Stevens and Michael Weber (pages 12-13 of 22).</small><!-- 2005 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2006</b> |
||
+ | <blockquote> |
||
+ | <b>Booch</b>: What would be your advice to somebody that would want to take up the banner of functional |
||
+ | programming? Where would you suggest they begin, and what hard problems would you like them to |
||
+ | pursue? |
||
+ | |||
+ | <b>Backus</b>: Well, trying to functionalize all the input/output stuff. |
||
+ | |||
+ | <b>Booch</b>: Helping it talk to the real world. |
||
+ | |||
+ | <b>Backus</b>: Yes. |
||
+ | |||
+ | :<small>[https://archive.computerhistory.org/resources/text/Oral_History/Backus_John/Backus_John_1.oral_history.2006.102657970.pdf Oral History of John Backus], Grady Booch (pages 36-37 of 42).</small><!-- 2006 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | A recognised difficulty with using monads to enforce single-threaded |
||
+ | access to the I/O world is that the programmer is forced |
||
+ | to over-sequentialize their I/O code: I/O operations that are |
||
+ | independent and which could be performed in any order still need to |
||
+ | be given an explicit ordering in the program. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.4188&rep=rep1&type=pdf Modelling Deterministic Concurrent I/O], Malcolm Dowse and Andrew Butterfield (page 2 of 12).</small><!-- 2006 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Monadic I/O [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.41.9361&rep=rep1&type=pdf <span></span>], |
||
+ | the standard approach to I/O in pure languages, forces the programmer to explicitly sequence all I/O |
||
+ | actions. This is not abstract at all, and is hardly a better specification of I/O than any C or |
||
+ | Pascal program. This opinion has been echoed by the functional language community. |
||
+ | |||
+ | :<small>[https://www.scss.tcd.ie/publications/tech-reports/reports.06/TCD-CS-2006-19.pdf A Semantic Framework for Deterministic Functional Input/Output], Malcolm Dowse (page 17 of 224).</small><!-- 2006 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | The downside of I/O using monads is the need for a monad that can not be |
||
+ | unwrapped. So, when using monadic I/O there is no way to get rid of the I/O |
||
+ | monad. Furthermore, it is not as intuitive as one would like it to be. A |
||
+ | prerequisite to good software design is a thorough understanding of the structures |
||
+ | and glues of the implementation language. Monads are an interesting addition to |
||
+ | both of these sets, and therefore a design implication is that the designer needs |
||
+ | to be aware of the potential benefits of using monads. Yet the |
||
+ | understanding of monads is not trivial. The extensive amount of tutorials and |
||
+ | questions on the Internet strengthen this thought. Another disadvantage is that |
||
+ | monads tend to be an all-or-nothing solution[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.91.3579&rep=rep1&type=pdf </span></span>]. The transition |
||
+ | from no interaction at all to a single form of interaction is not very smooth. |
||
+ | Parts of the program need to be rewritten. |
||
+ | |||
+ | :<small>[https://essay.utwente.nl/57287/1/scriptie_Rorije.pdf Input/Output in Functional Languages (Using Algebraic Union Types)], R.J. Rorije (page 30 of 130).</small><!-- 2006 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2007</b> |
||
+ | <blockquote> |
||
+ | The common practice of mixing IO with functionality inhibits composability whether in C or in Haskell. |
||
+ | |||
+ | :<small>[https://conal.net/blog/posts/tangible-functional-programming-a-modern-marriage-of-usability-and-composability Tangible Functional Programming: a modern marriage of usability and composability], Conal Elliott.</small><!-- 2007 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | [...] the next question that always comes up is how to do IO down in an function (in an expression) down a ways in the code. This often involves rewriting those "expressions" into "commands". |
||
+ | |||
+ | :<small>[http://blog.sigfpe.com/2007/11/io-monad-for-people-who-simply-dont.html#6353382341670425040 The IO Monad for People who Simply Don't Care], <q>jefu</q>.</small><!-- 2007 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2008</b> |
||
+ | <blockquote> |
||
+ | [...] for a long time [interaction] was seen as one of the major obstacles |
||
+ | for functional programming. The issues are now better understood, and two |
||
+ | workable solutions have emerged (uniqueness typing and monadic I/O). |
||
+ | Nevertheless, the last word on this issue has not yet been said. |
||
+ | |||
+ | :<small>[https://edsko.net/pubs/thesis.pdf Making Uniqueness Typing Less Unique], Edsko de Vries (page 23 of 264).</small><!-- 2008 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Support for [external] state in Haskell exists in the form of the I/O monad[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.9725&rep=rep1&type=pdf <span></span>], but in our opinion the monadic idiom does not scale well to large, complexly stateful programs, and imposes constraints that are unnatural in the eyes of systems programmers. |
||
+ | |||
+ | :<small>[https://web.archive.org/web/20081212233905/http://www.bitc-lang.org/docs/bitc/bitc-origins.html The Origins of the BitC Programming Language], Jonathan Shapiro, Swaroop Sridhar and M. Scott Doerrie.</small><!-- 2008 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Supporting IO would require us to extend our heap model to |
||
+ | include relevant aspects of the outside system, plus some kind of nondeterminism for |
||
+ | IO actions to take into account that we can never model the world in its entirety. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.176.4954&rep=rep1&type=pdf Imperative Functional Programming with Isabelle/HOL], Lukas Bulwahn, Alexander Krauss, Florian Haftmann, Levent Erkök and John Matthews (page 15 of 16).</small><!-- 2008 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2009</b> |
||
+ | <blockquote> |
||
+ | Writing solutions that are both elegant and efficient for applications that perform |
||
+ | substantial I/O or transform graph-structured data is still a challenge. |
||
+ | |||
+ | :<small>[https://www.cs.kent.ac.uk/pubs/2009/2874/content.pdf Functional Programming], Olaf Chitil (page 20 of 23).</small><!-- 2009 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | As Amdahl’s law states |
||
+ | [https://www3.cs.stonybrook.edu/~rezaul/Spring-2012/CSE613/reading/Amdahl-1967.pdf <span></span>], |
||
+ | the overall speedup that can be achieved |
||
+ | is determined not by the parallel parts of a program but by its |
||
+ | sequential segments. This becomes even more true with increasing |
||
+ | numbers of processing units. Therefore, we believe that even partly |
||
+ | lifting the requirement of strictly sequential I/O can be hugely |
||
+ | beneficial. |
||
+ | :<small>[https://www.sac-home.org/_media/publications:pdf:2009_6.pdf Controlling Chaos: On Safe Side-Effects in Data-Parallel Operations], Stephan Herhut, Sven-Bodo Scholz and Clemens Grelck (page 2 of 9).</small><!-- 2009 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2010</b> |
||
+ | <blockquote> |
||
+ | Input/output is awkward in declarative languages [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.13.9123&rep=rep1&type=pdf <span></span>]. |
||
+ | Some functional languages like LISP have procedural read and write operations. |
||
+ | Prolog has ugly read and write "predicates" that execute in sequence. |
||
+ | Haskell monads provide pure functional I/O but still involve a sequence of actions. |
||
+ | |||
+ | :<small>[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.227.6709&rep=rep1&type=pdf Specifying Input/Output by Enumeration], Walter W. Wilson and Yu Lei (first page).</small><!-- 2010 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | [...] where would I read up more on how we'd get rid of the imperative stuff entirely, [going] purely functional, and still have terminal interaction? |
||
+ | |||
+ | :<small>[https://conal.net/blog/posts/the-c-language-is-purely-functional#comment-487 The C language is purely functional], Raoul Duke.</small><!-- 2010 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Anyone expecting to use Haskell for primarily I/O related stuff is going to die from frustration. |
||
+ | |||
+ | :<small>[https://otherlibrarian.wordpress.com/2010/09/09/part-ii-how-not-to-start-your-haskell-program Part II: How not to Start Your Haskell Program], Ryan Deschamps.</small><!-- 2010 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2011</b> |
||
+ | <blockquote> |
||
+ | A potential drawback of monads, is that they force the use of |
||
+ | a single environment, to be passed between all I/O operations |
||
+ | within a program, effectively sequentialising all I/O operations. |
||
+ | |||
+ | :<small>[https://www.owenstephens.co.uk/assets/static/research/masters_report.pdf Approaches to Functional I/O], Owen Stephens (page 5 of 8).</small><!-- 2011 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Once you’re in the IO monad, you’re stuck there forever, and are reduced to Algol-style imperative programming. You cannot easily convert between functional and monadic style without a radical restructuring of code. |
||
+ | |||
+ | :<small>[https://existentialtype.wordpress.com/2011/05/01/of-course-ml-has-monads Of Course ML Has Monads!], Robert Harper.</small><!-- 2011 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Functional languages have many advantages— |
||
+ | being mathematical in nature, it is relatively easy to prove correctness of their |
||
+ | programs—so we would like a way to mimic, in a functional manner, non-functional |
||
+ | side-effects such as input/output and mutable state. |
||
+ | |||
+ | :<small>[https://math.uchicago.edu/~may/VIGRE/VIGRE2011/REUPapers/Berger.pdf On Some Aspects of The Theory of Monads], Carsen Berger (page 14 of 16).</small><!-- 2011 --> |
||
+ | </blockquote> |
||
+ | |||
+ | ---- |
||
+ | <b>2013</b> |
||
+ | <blockquote> |
||
+ | IO in Haskell [is] for me a source of great displeasure and it just defeated every try I have given to learn the language. |
||
+ | |||
+ | :<small>[https://www.haskellforall.com/2013/01/introduction-to-haskell-io.html?showComment=1361296801442#c794624017122358881 Introduction to Haskell <code>IO</code>], Ludovic Kuty.</small><!-- 2013 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Purity is pretty much |
||
+ | required for lazy languages, but I/O is very clumsy in pure languages so monadic |
||
+ | I/O was invented for Haskell to solve this problem [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.168.4008&rep=rep1&type=pdf <span></span>]. |
||
+ | |||
+ | :<small>[https://ntnuopen.ntnu.no/ntnu-xmlui/bitstream/handle/11250/253137/618488_FULLTEXT01.pdf?sequence=1 Trace-based just-in-time compiler for Haskell with RPython], Even Wiik Thomassen (page 15 of 96).</small><!-- 2013 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2014</b> |
||
+ | <blockquote> |
||
+ | Understanding I/O in Haskell, which implies understanding Monads (at least, the <code>IO</code> Monad) is actually one of the major difficulties I’ve came across while learning Haskell [...] |
||
+ | |||
+ | :<small>[https://discuss.codechef.com/t/is-it-possible-to-solve-tsort-with-haskell/4450/2 Is it possible to solve TSORT with Haskell?], Bruno Oliveira.</small><!-- 2014 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Here you’re equating functional languages with the inability to make use of benign effects, such as instrumentation of code for profiling purposes, which is indeed very clumsy in Haskell (you either have to rewrite your code to be imperative so that it conforms to the <code>IO</code> Monad, or else you have to admit that you really want ML [or perhaps HasFuse[https://www2.ki.informatik.uni-frankfurt.de/research/diamond/hasfuse/index.html <span></span>]] by using <code>unsafePerformIO</code>). |
||
+ | |||
+ | :<small>[https://www.pl-enthusiast.net/2014/09/02/who-teaches-functional-programming/#comment-564 Who teaches functional programming?], Robert Harper.</small><!-- 2014 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | Although the functional programming community has solved many of the difficulties |
||
+ | in implementation and use of functional languages, more research is needed on |
||
+ | several issues of importance to the real world: on facilities for input/output, |
||
+ | nondeterministic, realtime, parallel, and database programming. |
||
+ | |||
+ | :<small>[https://john.cs.olemiss.edu/~hcc/csci555/notes/haskell_notes.pdf Notes on Functional Programming with Haskell], H. Conrad Cunningham (page 21 of 192).</small><!-- 2014 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2015</b> |
||
+ | <blockquote> |
||
+ | [...] you shouldn't spend much time writing <code>IO</code> stuff, because it's a bad language embedded in a good one. |
||
+ | |||
+ | :<small>[https://web.archive.org/web/20220309052143/http://comonad.com/reader/2015/on-the-unsafety-of-interleaved-io On the unsafety of interleaved I/O], Dan Doel.</small><!-- 2015 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2016</b> |
||
+ | <blockquote> |
||
+ | <code>IO</code> is indeed a monad instance, but not a very nice |
||
+ | one - the compiler treats it specially, and it is not |
||
+ | very nice to reason about it - instead, we shall explore some |
||
+ | monads which do not put into question Haskell’s purity. |
||
+ | |||
+ | :<small>[https://nickhu.co.uk/Monads.pdf Understanding Monads], Nick Hu (first page).</small><!-- 2016 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | As an example, consider some code that needs access to the current time. This is something that would normally require <code>IO</code>, but we likely want to be able to use the value in a pure context without “infecting” the entire program with <code>IO</code> types. |
||
+ | |||
+ | :<small>[https://lexi-lambda.github.io/blog/2016/06/12/four-months-with-haskell Four months with Haskell], Alexis King.</small><!-- 2016 --> |
||
+ | </blockquote> |
||
+ | |||
+ | <blockquote> |
||
+ | The illusion is so good that programmers are fooled into thinking I/O is pure in Haskell. And now that we can write mostly pure code with occasional impure wrappers, researchers have mostly stopped seeking superior alternatives. |
||
+ | |||
+ | :<small>[https://crypto.stanford.edu/~blynn/haskell/io.html A Problem With I/O], Ben Lynn.</small><!-- 2016 --> |
||
+ | </blockquote> |
||
+ | ---- |
||
+ | <b>2017</b> |
||
+ | <blockquote> |
||
+ | I like the concise way of coding pure functions in Haskell using mathematical ideas like recursion and list comprehensions. However, user interactions are quite painful to implement using the I/O monad. |
||
+ | |||
+ | :<small>[https://www.linkedin.com/pulse/definition-functional-programming-rainer-grimm The Definition of Functional Programming], Dirk Verlinden.</small><!-- 2017 --> |
||
+ | </blockquote> |
||
− | * [https://accu.org/index.php/journals/2199 On Zero-Side-Effect Interactive Programming, Actors, and FSMs], Sergey Ignatchenko. <!-- 2016 --> |
||
+ | [[Category:Mathematics]] |
||
[[Category:Research]] |
[[Category:Research]] |
Latest revision as of 12:00, 2 August 2024
Functional languages are entirely mathematical, so the places where they don't work show where computing is not mathematics and help to illuminate both fields.
- Real Programming in Functional Languages, James H. Morris (page 33 of 36).
One of those places is I/O:
For Turing's [automatic] machine, a calculation begins with a problem on its tape, and ends with an answer there. For Church's calculus, reduction begins with a lambda term, and ends with its normal form. For Floyd's flowcharts and Hoare's triples, a program begins in a state satisfying a precondition, and ends in a state satisfying a postcondition. How the initial tape or term or state is input, and how the final one is output, are questions neither asked nor answered.
- How to Declare an Imperative, Philip Wadler (pages 1-2 of 33).
The problem is mathematical in origin
The various fields of study collectively referred to as mathematics are abstract in one or more ways:
In a preliminary sense, mathematics is abstract because it is studied using highly general and formal resources.
For a declarative programming language like Haskell, which is based on one of these individual fields of study - higher-order functions - being so abstract then raises the question of I/O and its observable effects:
How must interactions between a program and an external environment (consisting of, e.g., input/output-devices, file systems, ...) be described in a programming language that abstracts from the existence of an outside world?
- Functions, Frames and Interactions, Claus Reinke (page 10 of 210).
and effects more generally, with a preference for a denotational (as opposed to inexplicable) semantics:
During the 1960s, several researchers began work on proving things about programs. [...]
Several difficult problems emerged from this work. One was the problem of specification: before one can prove that a program is correct, one must specify the meaning of "correct", formally and unambiguously. Formal systems for specifying the meaning of a program were developed, and they looked suspiciously like programming languages.
Researchers began to analyze why it is often harder to prove things about programs written in traditional languages than it is to prove theorems about mathematics. Two aspects of traditional languages emerged as sources of trouble because they are very difficult to model in a mathematical system: mutability and sequencing.
- The Anatomy of Programming Languages, Alice E. Fischer and Frances S. Grodzinsky (page 353 of 600).
- mutability:
There is in principle nothing to stop functional programs from passing a single extra parameter into and out of every single function in the entire system. If this extra parameter were a collection (compound value) of some kind then it could be used to simulate an arbitrarily large set of mutable variables. In effect this approach recreates a single pool of global variables - hence, even though referential transparency is maintained, ease of reasoning is lost (we still know that each function is dependent only upon its arguments, but one of them has become so large and contains irrelevant values that the benefit of this knowledge as an aid to understanding is almost nothing).
- Out of the Tar Pit, Ben Moseley and Peter Marks (page 17 of 66).
- sequencing:
We have experimented for some time with a means for the programmer to specify a ‘syntactic’ partial order between subexpressions, with the intended effect that the ‘semantic’ order in which the input actions occur during the evaluation is not in conflict with the specified ‘syntactic’ partial order on the subexpressions (which carries over to the input actions evoked by those subexpressions). As a consequence, whenever the evaluator is about to execute an input action, it first has to decide whether there will occur in the future another input action that should be done first according to the specified ‘syntactic’ partial order. That problem, however, is undecidable.
- An alternative approach to I/O, Maarten Fokkinga and Jan Kuper (page 6 of 12).
The technical difficulty
In 1994 researchers showed that mutability and sequencing, if restricted, could be used anonymously in Haskell:
The reason for introducing a different monad
ST
, rather than just providing these operations over theIO
monad, is that destructive updates to variables in a program are not externally visible side-effects. We can therefore encapsulate these imperative effects [...] UsingrunST
we can write pure (non-monadic) functions whose implementation uses imperative features internally.
- Monads and Effects, Nick Benton, John Hughes and Eugenio Moggi (pages 33-34 of 82).
So I/O is a problem because of its external visibility, and that visibility demands the side effects of I/O have the appropriate sequencing:
By introducing side effects in expressions, the semantics becomes significantly more complex. At the same time, several issues arise, related to the evaluation order, i.e. the order in which the subparts of an expression are evaluated. If the evaluation order is not strictly defined, the presence of side effects in expressions is a source of non-deterministic behaviour.
- Denotational Semantics of Evaluation Order in Expressions with Side Effects, Nikolaos S. Papaspyrou (first page).
When combining effects, their order is often highly important (the reader might want to try different combinations of the effects “Open door”, and “Walk through door”, for example).
- Fudgets – Purely Functional Processes with applications to Graphical User Interfaces, Magnus Carlsson and Thomas Hallgren (page 12 of 263).
...and the machinery which runs our programs relies on mutability:
An “automatic” machine becomes a “choice” machine as soon as we allow the machine’s tape to be modified by external entities: the tape itself becomes a means of communication. This is essentially what happens in “real” computers (memory-mapped I/O); for example, we can write to the computer’s screen by modifying one particular area of memory, or find out which key was pressed on the computer’s keyboard by reading another.
It is less obvious how to add interaction to the lambda calculus.
- Making Uniqueness Typing Less Unique, Edsko de Vries (page 23 of 264).
Stream transformers are fragile to use, continuations are powerful but somewhat clutter the syntax of functions. Monads and uniqueness types both present a trade-off, do we accept the over-sequentialisation imposed by monads, or the visual disorder of explicit environment passing? We believe that a compromise is still to be found [...]
- Approaches to Functional I/O, Owen Stephens (final page).
Using prior research:
The theory of relative computability developed by Turing and Post and the o-machines provide a precise mathematical framework for interactive or online computing just as Turing a-machines provide one for offline computing processes such as batch processing.
- Turing-Post Relativized Computability and Interactive Computing, Robert Irving Soare (page 7 of 76).
a more satisfactory solution could be obtained. Another possibility is a completely-new discovery: the investigation continues. In the meantime, those who work with programming languages will have to contend with I/O as best they can:
By its very nature I/O does not fit in well with programming language design. Every language designer has encountered the problem that the task of including usable I/O facilities invariably seems to make it necessary to break some of the rules or design principles of the language. In many languages with clean and simple concepts I/O is the "odd one out".
- I/O Considered Harmful (At Least for the First Few Weeks), John Rosenberg and Michael Kölling (first page).
[...] I/O calls are side effects and make impure functions. Impure functions are hard to test.
- Refactoring JavaScript, Evan Burchard (page 437 of 499).
...especially considering the ever-expanding state space in which memory-mapped I/O resides:
Definition 6.1. A state is an element of 2n for some fixed n; that is, it is a finite sequence of 1s and 0s. The space 2n is called the state space.
The number n is the size of the memory in bits, and will usually be rather large. On modern personal computers at the time of this writing, n would be on the order of several billion.
- On Some Aspects of The Theory of Monads, Carsen Berger (page 14 of 16).
An axiomatic approach
The dependently-typed language Agda relies on Haskell for its outside interactions:
4 Compiling Agda programs
This section deals with the topic of getting Agda programs to interact with the real world. Type checking Agda programs requires evaluating arbitrary terms, ans as long as all terms are pure and normalizing this is not a problem, but what happens when we introduce side effects? Clearly, we don't want side effects to happen at compile time. Another question is what primitives the language should provide for constructing side effecing programs. In Agda, these problems are solved by allowing arbitrary Haskell functions to be imported as axioms. At compile time, these imported functions have no reduction behaviour, only at run time is the Haskell function executed.
- Dependently Typed Programming in Agda, Ulf Norell and James Chapman (page 38 of 41).
Haskell's FFI also allows for arbitrary foreign code to be imported, to only be executed at run time:
instance Monad IO where
return = unitIO
(>>=) = bindIO
foreign import ccall "primUnitIO" unitIO :: a -> IO a
foreign import ccall "primBindIO" bindIO :: IO a -> (a -> IO b) -> IO b
⋮
However, Haskell 2010 doesn't allow higher-order FFI declarations, or their use of type variables. Visible implementations of monadic I/O based on other interfaces are another option, but Haskell 2010 also imposes restrictions on its I/O type:
The
IO
type serves as a tag for operations (actions) that interact with the outside world. TheIO
type is abstract: no constructors are visible to the user.
- The Haskell 2010 Report (page 95 of 329).
On being denotative
While the prevailing approach to I/O is based on combining the imperative and functional programming styles:
The special claim of ISWIM is that it grafts procedural notions onto a purely functional base without disturbing many of the desirable properties.
- The Next 700 Programming Languages, Peter J. Landin (page 8 of 10).
We need the concept of a ‘process’ as opposed to a function. Intuitively a process is something that (in general) is geared towards continuation while a function is geared towards termination. Processes have an input channel on which an input stream (a potentially infinite sequence of tokens) is coming in and an output channel on which an output stream is coming out. A typical process is the control of a traffic light system: it is geared towards continuation, there is an input stream (coming from the pushbuttons for pedestrians) and an output stream (regulating the traffic lights). Text editing is also a process. In fact, even the most simple form of I/O is already a process.
- The impact of the lambda calculus in logic and computer science, Henk Barendregt (page 21 of 36).
which is achieved in Haskell by using types:
The main program (function
main
from moduleMain
, which we writeMain.main
) has typeIO ()
, that is, it is a computation which performs some I/O and returns an uninteresting result. The "trivial" type()
has only one value, the unit value, which is also written()
.
- Monadic I/O in Haskell 1.3, Andrew D. Gordon and Kevin Hammond.
...there has also been interest in using denotational semantics or models due to the advantages they provide:
For example, there are several simple variations on the model for processes [].
In the face of such an abundance, it is best to recall the motivation for seeking such models. They provide a useful mathematical framework for the analysis of programs, and for developing logical systems for proving their properties.
- Algebraic Laws for Nondeterminism and Concurrency, Matthew Hennessy and Robin Milner (first page).
But there is an important prerequisite that needs to be observed when attempting to use such models:
[...] if either the mathematics or the logic is to have any relevance, a link must be made between the denotational model and the behavior, or operational semantics, of the programs.
So while only having an operational semantics for IO a
might
not
be ideal,
only having a denotational model:
(page 19 of 60)
type IO a = World -> (a, World) type IO a = (a, Set Trace) type Trace = [Event] data Event = PutChar Char | GetChar Char | ...
...would be insufficient:
It is all very well to aim for a more "abstract" and a "cleaner" approach to semantics, but if the plan is to be any good, the operational aspects cannot be completely ignored. The reason is obvious: in the end the program still must be run on a machine - a machine which does not possess the benefit of "abstract" human understanding, a machine that must operate with finite configurations.
- Outline of a Mathematical Theory of Computation, Dana Scott (page 8 of 30).
[...] The meaning of a conventional computer program, as far as a user is concerned, is just the mathematical function it evaluates. But we users are inside our interactive systems; we care about what continually goes on. The meaning surely lies in the whole conversation, not just its end-result. (Indeed there may be no end-result, since there may have been no goal.)
- Turing, Computing and Communication, Robin Milner (page 8 of 12).
The procedural boundary
In theory, a procedure could be given one or more input registers as arguments and write the result directly to an output register. So if the contents of the input registers change while the procedure is running, its eventual result could be based on some combination of old and new input data. This, while possibly annoying, is to be expected: procedures are allowed to provide different results for the same arguments.
In practice, one or more procedures are given most, if not all I/O registers along with all available memory addresses. Together with other procedures (and some functions), they form the kernels of most contemporary operating systems.
But for a function, such conspicuous variability in its given arguments is untenable:
- while a function is being evaluated to obtain a result,
- and the result is still being used (it may contain arguments, or be one of them),
the values of its arguments must be kept constant for the result to be correct.
This requirement presents serious difficulties for the direct use of I/O registers with functions:
- evaluation of a function can take an arbitrarily-long time to complete,
- and providing the result to an external entity could also be slow to finish (the result could be large).
In essence, if a function were to use I/O registers directly, they would have to behave like memory addresses. But that is contrary to the intended purpose of I/O registers! Therefore it is usually easier for the exchange of data between programs and I/O registers to be managed by procedures (or actions in House), with most other work being done by functions.
Seeking freedom
It has been proclaimed that:
The monad constructor
IO
is a liberation to the purist functional programmer in that it permits expression of arbitrary imperative commands within a higher-order type-secure language.
- Monadic I/O in Haskell 1.3, Andrew D. Gordon and Kevin Hammond.
But Haskell implementations are written, partly or completely, in another I/O-capable programming language. So if it's already in those implementations, does I/O also have to be present in Haskell?
Instead of putting I/O into the functional programming model (as in continuation- and stream-based I/O), or adopting a hybrid functional/imperative model (as in monadic I/O), let’s explore how to move I/O entirely out of our programming model into the implementation of a denotationally simple model for whole systems.
Variations of this arrangement have been used in the designs of some early functional languages:
One way to deal with this is the so called standard solution The purely functional reduction machine is attached to a von Neumann host machine and an imperative environment deals with I/O and interactive programs.
- Functional programming and the language TALE, Henk Barendregt and Marc van Leeuwen (page 6 of 88).
Another idea is to embed the functional language in an imperative one, which performs all input and output operations.
- The implementation of functional languages using custom hardware, William Stoye (page 80 of 142).
However:
The disadvantage of this approach is that in many cases it results in a substantial fraction of the total programming effort being expended on developing code in the imperative language. If functional languages are the best tool for writing programs, then this should be regarded as a defeat (if they're not, none of this is important). Thus, we must experiment with extending functional programming techniques to cover interaction and control operations as much as possible.
There have been other problems:
[...] designers [of Algol 60] felt that input and output were too machine-dependent to be made part of the definition of a universal language; as a result, the original language definition did not include any input or output construct, which led every compiler writer to design his own – not a very pleasant situation for users concerned with portability. (Later versions of Algol 60 defined a standard mechanism.)
- Introduction to the Theory of Programming Languages, Bertrand Meyer (page 214 of 459).
As a result:
More recent designs such as C, Ada and Eiffel keep input-output mechanisms out of the language, in the Algol tradition, but do not shirk their responsibilities since they define one or more standard input-output libraries.
A historical note
The stream-based (or dialogue) I/O model provided in Haskell prior to version 1.3 required substantial support from implementations e.g. by using an imperative “wrapper”:
It repeatedly takes a request off the result list, acts on the request, and attaches an appropriate response to the argument list. There has be some clever footwork to deal with the fact that the function has to be applied to a list of responses before there are any responses in the list, but that isn’t a problem in a lazy setting.
- Tackling the Awkward Squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell, Simon Peyton Jones (pages 4-5 of 60).
So why was it replaced?
[...] it has several defects:
- It is hard to extend. New input or output facilities can be added only by extending the
Request
andResponse
types, and by changing the “wrapper” program. Ordinary users are unlikely to be able to do this.
- There is no very close connection between a request and its corresponding response. It is extremely easy to write a program that gets one or more “out of step”.
- Even if the program remains in step, it is easy to accidentally evaluate the response stream too eagerly, and thereby block emitting a request until the response to that request has arrived – which it won’t.
The monadic interface helped to shift the first problem - the difficulty of extending - out of those early Haskell implementations:
- It is easily extensible. The key to our implementation is to extend Haskell with a single form that allows one to call an any procedure written in the programming language C , without losing referential transparency (Section 2.3). Using it programmers can readily extend the power of the I/O system, by writing Haskell functions which call operating system procedures.
- Imperative functional programming Simon Peyton Jones and Philip Wadler (first page).
This made it possible to define dialogue I/O, “wrapper” and all, in Haskell:
The entire I/O system provided by our compiler is written in Haskell, using the non-standard extensions we describe below. The language’s standard
Dialogue
interface for I/O is supported by providing a function to convert aDialogue
into ourIO
monad.
- (second page).
Any proposal which involves shifting I/O back into modern Haskell implementations must therefore have a practical solution to that original problem - the difficulty of extending implementations.
Open questions
- Is there an alternate standalone model of I/O with less problems than each of the current models?
- If not, can I/O be moved away from the language (as a model) and into the implementation (thus making the language denotative), while keeping the resulting language relatively practical to use?
Other questions
- Is the C language "purely functional"?
- No:
- C isn't "pure" - it allows unrestricted access to observable effects, including those of I/O.
- C isn't "functional" - it was never intended to be referentially transparent, which severely restricts the ability to use equational reasoning.
- No:
- Is the Haskell language "purely functional"?
- Haskell is not a purely functional language, but is often described as being referentially transparent.
- Why do our programs need to read input and write output?
- Because programs are usually written for practical purposes, such as implementing domain-specific little languages like Dhall.
Other articles
- LOGLISP: an alternative to PROLOG, John A. Robinson and Ernest E. Sibert.
- A New Scheme for Writing Functional Operating Systems, William Stoye.
- Functional Programming with Side Effects, Mark B. Josephs.
- The Semantics of an FP Language with Infinite Objects, Teresa Thomas.
- A Mathematical Approach to Nondeterminism in Data Types, Wim H. Hesselink.
- Assignments for Applicative Languages, Vipin Swarup, Uday S. Reddy and Evan Ireland.
- TIP in Haskell – Another Exercise in Functional Programming, Colin Runciman.
- A Functional Approach to Graphics Programming and Modeling, S. Ramakrishnan.
- Imperative Functional Programming, Uday S. Reddy.
- A representable approach to finite nondeterminism, S. O. Anderson and A. J. Power.
- Directions in Functional Programming for Real(-Time) Applications, Walid Taha, Paul Hudak and Zhanyong Wan.
- Reactive Objects, Johan Nordlander, Mark P. Jones, Magnus Carlsson, Richard B. Kieburtz, and Andrew Black.
- Can GUI Programming Be Liberated From The IO Monad, John Peterson, Antony Courtney and Henrik Nilsson.
- Witnessing Side Effects, Tachio Terauchi and Alex Aiken.
- Programming Languages For Interactive Computing, Roly Perera.
- Heap Recycling for Lazy Languages, Jurriaan Hage and Stefan Holdermans.
- A Functional I/O System, Matthias Felleisen, Robert Bruce Findler, Matthew Flatt and Shriram Krishnamurthi.
- Single Assignment C (SAC): High Productivity Meets High Performance, Clemens Grelck.
- The Night Watch, James Mickens.
- Combining Effects and Coeffects via Grading, Marco Gaboardi, Flavien Breuvart, Shin-ya Katsumata, Dominic Orchard and Tarmo Uustalu.
- Mathematical mysteries, Plus magazine.
More quotes
1978
The primary limitation of FP systems is that they are not history sensitive. Therefore they must be extended somehow before they can become practically useful.
- Can Programming Be Liberated from the von Neumann Style? A Functional Style and Its Algebra of Programs, John Backus (page 11 of 29).
1980
An other important point is that FP systems [...] have no means to save definitions or results produced by a computation and to recall them later. Therefore, they must be imbedded into an environment capable of performing these tasks for them.
- FAD, a Functional Programming Language that Supports Abstract Data Types, Johannes J. Martin (page 2 of 16).
1984
[...‘stream-processing’ solutions based on] systems of communicating processes can be described in a purely functional language by recursion over infinite lists; this is important because it open up the way for problems involving input–output and communication to be dealt with cleanly within the functional style [].
- Functional Programs as Executable Specifications: Discussion, David A. Turner (page 17 of 27).
1986
Functional languages are extremely powerful and succinct tools for expressing algorithms, but the way in which the results of such calculations should be communicated to the outside world is not obvious.
- Message-based functional operating systems, William Stoye (first page).
Input and output are perhaps the most systematically neglected features of programming languages. They are usually ad hoc, and they are usually poorly integrated with the other facilities of their hosts – the languages in which they are embedded.
- An Input-Output Model for Interactive Systems, Mary Shaw (first page).
1987
The utility of the different programming style imposed by restricting side-effects is debatable, but it is fair to say that operations such as input and output (since they are history sensitive — i.e. they are inherently side-effects) are particularly awkward to express.
- The Refined-Language Approach To Compiling For Parallel Supercomputers, Henry G. Dietz (page 34 of 188).
1989
Is there any hope of achieving purely functional, yet universal, and of course efficient I/O?
- On the Expressiveness of Purely Functional I/O Systems, Paul Hudak and Raman S. Sundaresh (page 2 of 29).
It is not clear how one might express an interactive process as a function — this is still a research topic, see for example Interactive functional programs: a method and a formal semantics.
- The design and implementation of an operating system in a functional language, John R. G. Cupitt (page 10 of 150).
Starting with Landin streams many I/O schemes have been proposed for purely functional languages, but they tend to be ad hoc in the sense of being designed to express particular kinds of I/O, without aiming for universal power.
- PFL+: a kernel scheme for functional I/O, Andrew Gordon (page 4 of 28).
A straightforward example of such a problematical application is that of a function which could allow us to interactively query and modify a database; this is clearly an interactive problem, since we may only be able to formulate queries once we have seen the responses to earlier ones.
- Functional Programming and Operating Systems, Simon B. Jones and A. F. Sinclair (first page).
At present most declarative languages are guest languages on [...] procedural machines, and able to preserve their data in the file system provided by the host machine. However, the interface to the file system that is provided by the guest languages is primitive and often not referentially transparent.
- A Functional Database, Phil Trinder (page 14 of 210).
1990
A functional program transforms data into other data according to a certain algorithm. Functional programs cannot deal with input/output, cannot switch on and off lamps depending on the value of a certain parameter; in general they cannot deal with process control.
- Functional Programming and Lambda Calculus, Henk Barendregt (page 324).
To maintain correct I/O behaviour the relative temporal ordering of individual I/O operations must be controlled. [...] However, in pure functional languages, as they are referentially transparent, there is usually no mechanism to control the temporal ordering of the evaluation, hence maintaining correct I/O behaviour is non-trivial3. [...]
3It is non-trival as a programmer needs always to be considering how something will be executed – which is only possible with a thorough understanding of the evaluation strategy/denotational semantics. It is also a task from which functional programming is usually claimed to relieve the programmer.
- The implementation of practical functional programming languages, Nigel Perry (page 18 of 144).
1991
Input and output do not require justification: a program without communication with the outside world is of little use.
- Introduction to the Theory of Programming Languages, Bertrand Meyer (page 214 of 459).
1992
One consequence of referential transparency is that it is difficult to incorporate I/O into a pure functional language. [...] Alternative models have been proposed which do not suffer from this difficulty; see for example the Haskell [version 1.1] report, which attempts to represent the current consensus in the field. Nonetheless, these other models are notationally complex, and I/O modeling remains a problem.
- Using a Lazy Functional Language for Textual Information Retrieval, Donald Ziff, Keith Waclena, and Stephen Spackman (page 3 of 13).
A lot has been said in favour of functional programming but the fact is that functional programming suffers from a paramount lack of appreciation in the established programming society. For one reason this is caused by the fact that only recently functional programs have gained execution speeds comparable to their imperative rivals . Another important reason is that functional programming defected on performing input output (I/O hereafter) with the outer world.
I/O and functional programming doesn’t seem to be unifiable: functional languages don’t have the notion of side-effects and lack a precise control of the evaluation order. These are precisely the important aspects for any I/O model. There have been many proposals how to deal with I/O (see section 8) but none of them are completely satisfactory. In particular it is very hard to deal with the side-effect problem.
- High Level Specification of I/O in Functional Languages, Peter Achten, John van Groningen, Rinus Plasmeijer (pages 1-2 of 17).
1993
In the case of input/output, which typically takes the form of an ordered sequence of events, it has always been hard to deny convincingly that the imperative model is more intuitive. Functional models using streams or continuations have always been difficult to grasp at first, whereas practically anyone can quickly come to terms with the ‘input a; print a’ nature of basic (or BASIC) imperative languages.
- Animating Z specifications in Haskell using a monad, Howard S. Goodman (page 25 of 31).
A disadvantage of the [stream] method for writing interactive functional programs is that every part of the output has to be part of the result of the whole program on the top level. As a consequence it is not a trivial task to change a program in such a way that for a specific function that is used somewhere in an expression the value of its arguments is printed every time the function is called. A change like that, which can be of interest for tracing or debugging, requires a change of the structure of the whole program.
- Functional Programming and Parallel Graph Rewriting, Rinus Plasmeijer and Marko van Eekelen (page 82 of 623).
1994
Although the advantages of functional programming are fairly well known, a few areas have proved troublesome, I/O being one of these.
- Functional Languages and Graphical User Interfaces - a review and a case study, Rob Noble and Colin Runciman (page 6 of 51).
There are many attempts to integrate I/O into functional languages, such as linear types , and monads in Haskell, or uniqueness typing in Clean . These approaches have in common that the programmer explicitly has to create data dependencies among consecutive I/O operations which lead to very awkward notations.
- Single Assignment C - Functional Programming Using Imperative Style, Sven-Bodo Scholz (page 2 of 13).
1995
In pure functional languages, several proposals have been made for clean I/O models. We mention Landin’s streams, Monads, and Uniqueness Types. Compared to our approach, these models are more deterministic [when less is required], especially with respect to output. More generally, these models sequentialize I/O actions by imposing static constraints (usually expressed as types) on the program.
- A model for I/O in equational languages with don’t care non-determinism, H. R. Walters and J. F. Th. Kamperman (page 14 of 15).
If, however, we wish to classify programs that have potentially infinite behaviors, such as a program that echoes its input, then a more direct model of input-output seems necessary.
- Untyped Lambda-Calculus with Input-Output, Jerzy Tiuryn and Mitchell Wand (page 2 of 11)
1996
The programming style in a lazy functional language is heavily influenced by the supported I/O-mechanism. Modifying the I/O-behaviour or debugging some lazy functional program that uses I/O is a black art. It is interesting that novices in lazy functional programming in general expect that there is some direct (side-effecting) I/O using a function call.
- A Partial Rehabilitation of Side-Effecting I/O:, Manfred Schmidt-Schauß (first page).
No formal semantics for these I/O primitives is possible at present, because there is no complete formal semantics for Haskell itself. We hope in future that such a semantics will be developed. One task of such a semantics would be to show that the
IO
type does indeed form a monad in the categorical sense.
- Monadic I/O in Haskell 1.3, Andrew D. Gordon and Kevin Hammond.
For other models of computation like functional or logic programming, the typical approach has been to add extra features implementing I/O. But these features do not fit in the nice and simple underlying model: in order to be able to understand or reason about programs involving I/O, the basic computational model has to be extended in non trivial ways, making it not so nice and simple anymore [...]
- Input/Output for ELAN, Patrick Viry (first page).
1997
While it is fine that monadic I/O has good theoretical under-pinnings, did anyone stop to think if it helped in user interface programming? If all that it is is a means somehow to construct interactive programs, then it succeeds, but that is not enough. A programmer chooses a language based not on only on ability, but also usability.
- Interacting with Functional Languages, Duncan Sinclair (page 15 of 159).
1998
Uniqueness typing addresses the more general problem of statically controlled use of resources in functional programs and, even if combined with passing unique representations of environment objects as arguments to these programs, it does not suffice to solve the input/output-problem. The reason is that the environment is not updated in one conceptual step after the evaluation of a program has computed a new environment representation but rather in small steps whenever the environment representation is modified during program evaluation. The primitive interactions are thus implemented as side-effecting operations, the use of which is rendered safe in the uniqueness-typed environment passing framework.
Similarly, monads are used to address the more general problem of computations (involving state, input/output, backtracking, ...) returning values: they do not solve any input/output-problems directly but rather provide an elegant and flexible abstraction of many solutions to related problems [...]. For instance, no less than three different input/output-schemes are used to solve these basic problems in Imperative functional programming, the paper which originally proposed ‘a new model, based on monads, for performing input/output in a non-strict, purely functional language’. [...]
So, both input/output-schemes merely provide frameworks in which side-effecting operations can safely be used with a guaranteed order of execution and without affecting the properties of the purely functional parts of the language.
- Functions, Frames and Interactions, Claus Reinke (pages 96-97 of 210).
1999
Since I/O is by nature side effects, Haskell handles it differently. Monadic I/O is used to overcome this problem.
After overcoming Haskell's I/O, there were no more setbacks in writing the program.
- Functional Programming Using Haskell, Wade Estabrooks, Michael Goit and Mark Steeves.
Only theorists find it interesting to write programs that don’t require input or produce output.
- Java I/O, Elliotte Rusty Harold (page 21 of 479).
Ever since McCarthy referred to the input/output (I/O) operations
READ
and
- Relating Operational and Denotational Semantics for Input/Output Effects, Roy L. Crole and Andrew D. Gordon (page 2 of 38).
Something fundamental and innocent looking as simple I/O has been a hard problem for functional languages. Many models, such lazy streams, continuation semantics, and systems model have been proposed to overcome the discrepancy between a referential transparent language and I/O side effects. Hudak gives examples of the above I/O styles and although imperative syntax is mimicked they look very un-intuitive and cumbersome to someone used to plain I/O statements. Recently, a step forward has been made by employing so-called monads for I/O . This model has also been adopted for the latest revision for HASKELL [version 98]. It remains a matter of taste whether such a treatment of I/O state is conceived as natural or unacceptable.
- A Functional Pattern System for Object-Oriented Design, Thomas Kühne (page 40 of 346).
2001
Now that we have discussed the monadic approach in some detail, you may well be asking the following question: once we have added imperative-looking input/output, concurrency, shared variables, and exceptions, have we not simply re-invented good old procedural programming? Have we “lost the plot” [...]
- Tackling the Awkward Squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell, Simon Peyton Jones (page 55 of 60).
2002
In our approach, we would suggest to dismantle the
IO
monad into its constituting monads, and combine them with the coproduct as needed. This has the advantage that the effects of most monads can be localised, so using e.g. state threads or exceptions in one part of the program will not make the type of every function using this part monadic, as is currently the case with theIO
monad.
- Composing Monads Using Coproducts, Christoph Lüth and Neil Ghani (page 11 of 12).
2003
It is possible that a declarative programming style for the IO part of a program can be integrated into Haskell.
- Realising nondeterministic I/O in the Glasgow Haskell Compiler, David Sabel (page 37 of 39).
The common method to relieve the programming language designer from the inherent IO-problems is to shift responsibility to the programmer who has to sequentialize all IO-requests. This is also true for the monadic approach implemented in Haskell [version 98] .
- FUNDIO: A Lambda-Calculus With letrec, case, Constructors, and an IO-Interface:, Manfred Schmidt-Schauß (page 3 of 84).
2004
As for intrinsic advantage, I think Haskell has at least one obvious handicap -- monadic I/O. Every minute I spend trying to understand how to program with it is a minute I am solving a problem I don't care about.
- New Paul Graham thing,
sean.
2005
[...] doing IO in Haskell means using a polymorphic type as well as a mathematical theory that is rather obtuse. That's why IO is so far down in this tutorial.
- Haskell Tutorial for C Programmers, Eric Etheridge.
HASKELL uses monads for destructive updates and I/O; they add a restricted form of stateful computation to a pure language, retaining referential transparency . The disadvantage is that programs become more complicated. Also, if imperative elements of a given application were not taken into account during its design but turn out to be necessary later on, often major parts have to be redesigned or (at least) reimplemented, especially because types change significantly. [...]
The TRUTH team considers this point as one of the biggest drawbacks of the purely functional paradigm as followed by HASKELL.
- Functional programming languages for verification tools: A comparison of Standard ML and Haskell, Martin Leucker, Thomas Noll, Perdita Stevens and Michael Weber (pages 12-13 of 22).
2006
Booch: What would be your advice to somebody that would want to take up the banner of functional programming? Where would you suggest they begin, and what hard problems would you like them to pursue?
Backus: Well, trying to functionalize all the input/output stuff.
Booch: Helping it talk to the real world.
Backus: Yes.
- Oral History of John Backus, Grady Booch (pages 36-37 of 42).
A recognised difficulty with using monads to enforce single-threaded access to the I/O world is that the programmer is forced to over-sequentialize their I/O code: I/O operations that are independent and which could be performed in any order still need to be given an explicit ordering in the program.
- Modelling Deterministic Concurrent I/O, Malcolm Dowse and Andrew Butterfield (page 2 of 12).
Monadic I/O , the standard approach to I/O in pure languages, forces the programmer to explicitly sequence all I/O actions. This is not abstract at all, and is hardly a better specification of I/O than any C or Pascal program. This opinion has been echoed by the functional language community.
- A Semantic Framework for Deterministic Functional Input/Output, Malcolm Dowse (page 17 of 224).
The downside of I/O using monads is the need for a monad that can not be unwrapped. So, when using monadic I/O there is no way to get rid of the I/O monad. Furthermore, it is not as intuitive as one would like it to be. A prerequisite to good software design is a thorough understanding of the structures and glues of the implementation language. Monads are an interesting addition to both of these sets, and therefore a design implication is that the designer needs to be aware of the potential benefits of using monads. Yet the understanding of monads is not trivial. The extensive amount of tutorials and questions on the Internet strengthen this thought. Another disadvantage is that monads tend to be an all-or-nothing solution. The transition from no interaction at all to a single form of interaction is not very smooth. Parts of the program need to be rewritten.
- Input/Output in Functional Languages (Using Algebraic Union Types), R.J. Rorije (page 30 of 130).
2007
The common practice of mixing IO with functionality inhibits composability whether in C or in Haskell.
[...] the next question that always comes up is how to do IO down in an function (in an expression) down a ways in the code. This often involves rewriting those "expressions" into "commands".
2008
[...] for a long time [interaction] was seen as one of the major obstacles for functional programming. The issues are now better understood, and two workable solutions have emerged (uniqueness typing and monadic I/O). Nevertheless, the last word on this issue has not yet been said.
- Making Uniqueness Typing Less Unique, Edsko de Vries (page 23 of 264).
Support for [external] state in Haskell exists in the form of the I/O monad, but in our opinion the monadic idiom does not scale well to large, complexly stateful programs, and imposes constraints that are unnatural in the eyes of systems programmers.
- The Origins of the BitC Programming Language, Jonathan Shapiro, Swaroop Sridhar and M. Scott Doerrie.
Supporting IO would require us to extend our heap model to include relevant aspects of the outside system, plus some kind of nondeterminism for IO actions to take into account that we can never model the world in its entirety.
- Imperative Functional Programming with Isabelle/HOL, Lukas Bulwahn, Alexander Krauss, Florian Haftmann, Levent Erkök and John Matthews (page 15 of 16).
2009
Writing solutions that are both elegant and efficient for applications that perform substantial I/O or transform graph-structured data is still a challenge.
- Functional Programming, Olaf Chitil (page 20 of 23).
As Amdahl’s law states , the overall speedup that can be achieved is determined not by the parallel parts of a program but by its sequential segments. This becomes even more true with increasing numbers of processing units. Therefore, we believe that even partly lifting the requirement of strictly sequential I/O can be hugely beneficial.
- Controlling Chaos: On Safe Side-Effects in Data-Parallel Operations, Stephan Herhut, Sven-Bodo Scholz and Clemens Grelck (page 2 of 9).
2010
Input/output is awkward in declarative languages . Some functional languages like LISP have procedural read and write operations. Prolog has ugly read and write "predicates" that execute in sequence. Haskell monads provide pure functional I/O but still involve a sequence of actions.
- Specifying Input/Output by Enumeration, Walter W. Wilson and Yu Lei (first page).
[...] where would I read up more on how we'd get rid of the imperative stuff entirely, [going] purely functional, and still have terminal interaction?
- The C language is purely functional, Raoul Duke.
Anyone expecting to use Haskell for primarily I/O related stuff is going to die from frustration.
- Part II: How not to Start Your Haskell Program, Ryan Deschamps.
2011
A potential drawback of monads, is that they force the use of a single environment, to be passed between all I/O operations within a program, effectively sequentialising all I/O operations.
- Approaches to Functional I/O, Owen Stephens (page 5 of 8).
Once you’re in the IO monad, you’re stuck there forever, and are reduced to Algol-style imperative programming. You cannot easily convert between functional and monadic style without a radical restructuring of code.
- Of Course ML Has Monads!, Robert Harper.
Functional languages have many advantages— being mathematical in nature, it is relatively easy to prove correctness of their programs—so we would like a way to mimic, in a functional manner, non-functional side-effects such as input/output and mutable state.
- On Some Aspects of The Theory of Monads, Carsen Berger (page 14 of 16).
2013
IO in Haskell [is] for me a source of great displeasure and it just defeated every try I have given to learn the language.
- Introduction to Haskell
IO
, Ludovic Kuty.
Purity is pretty much required for lazy languages, but I/O is very clumsy in pure languages so monadic I/O was invented for Haskell to solve this problem .
- Trace-based just-in-time compiler for Haskell with RPython, Even Wiik Thomassen (page 15 of 96).
2014
Understanding I/O in Haskell, which implies understanding Monads (at least, the
IO
Monad) is actually one of the major difficulties I’ve came across while learning Haskell [...]
- Is it possible to solve TSORT with Haskell?, Bruno Oliveira.
Here you’re equating functional languages with the inability to make use of benign effects, such as instrumentation of code for profiling purposes, which is indeed very clumsy in Haskell (you either have to rewrite your code to be imperative so that it conforms to the
IO
Monad, or else you have to admit that you really want ML [or perhaps HasFuse] by usingunsafePerformIO
).
- Who teaches functional programming?, Robert Harper.
Although the functional programming community has solved many of the difficulties in implementation and use of functional languages, more research is needed on several issues of importance to the real world: on facilities for input/output, nondeterministic, realtime, parallel, and database programming.
- Notes on Functional Programming with Haskell, H. Conrad Cunningham (page 21 of 192).
2015
[...] you shouldn't spend much time writing
IO
stuff, because it's a bad language embedded in a good one.
- On the unsafety of interleaved I/O, Dan Doel.
2016
IO
is indeed a monad instance, but not a very nice one - the compiler treats it specially, and it is not very nice to reason about it - instead, we shall explore some monads which do not put into question Haskell’s purity.
- Understanding Monads, Nick Hu (first page).
As an example, consider some code that needs access to the current time. This is something that would normally require
IO
, but we likely want to be able to use the value in a pure context without “infecting” the entire program withIO
types.
- Four months with Haskell, Alexis King.
The illusion is so good that programmers are fooled into thinking I/O is pure in Haskell. And now that we can write mostly pure code with occasional impure wrappers, researchers have mostly stopped seeking superior alternatives.
- A Problem With I/O, Ben Lynn.
2017
I like the concise way of coding pure functions in Haskell using mathematical ideas like recursion and list comprehensions. However, user interactions are quite painful to implement using the I/O monad.
- The Definition of Functional Programming, Dirk Verlinden.