<div dir="ltr"><div><span><div>TL;DR: Evaluation is always pure[1]. Execution isn't, but it wasn't supposed to be in the first place.</div></span></div><div dir="ltr"><div><span><div><br></div><div>> <span>would it make sense to forget about effects and purity and distinguish only between IO and non-IO? It should be easy enough to tell IO from non-IO, no?</span></div></span></div></div><div dir="ltr"><div><span></span></div><div><br></div>There is no need to distinguish between IO and non-IO. Everything is pure, including IO.</div><div dir="ltr"><br></div><div dir="ltr">When people talk about effects, they tend to mean something encapsulated and "hidden" by the implementation of bind and return for a particular Monad instance; the meaning of "effect" is entirely dependent on this context. For example, State encapsulates the effect of passing an accumulating parameter to multiple functions and properly threading the results. Reader encapsulates additional function parameters that are never varied. Writer encapsulates writing to a "log" (any monoidal accumulator). The list monad encapsulates the effect of non-determinism (functions that can return more than one result), allowing you to work with placeholder variables that represent all possible results at that stage of the computation. ST encapsulates mutation in way that is *externally unobservable*. And so on. None of these "effects" are impure. They are all referentially transparent. They do not mutate any external or global state. They can all be rewritten by inlining the relevant definitions of bind and return in a way that will make it obvious that no "funny stuff" is happening.</div><div dir="ltr"><br></div><div dir="ltr">One important difference between this sort of encapsulation and the kind that you might find in an OOP language is that this encapsulation is *perfect*. These abstractions *do not leak*. There is no way for your program to externally observe any mutation during evaluation of a State action and the same holds, mutatis mutandis, for all the other monad instances.<div><br></div><div>IO is a common source of confusion, but the important distinction here is the one that Chris already made: *evaluation* of IO actions is pure, referentially transparent, and causes no effects (side- or otherwise). Execution of the `main` IO action by the runtime—and by extension the execution of those other IO actions that may compose it—is obviously not pure, but no one is expecting *execution* to be pure: if execution were required to be pure then the program couldn't be run at all, because any attempt to run it would cause some sort of externally observable effect (even if it merely heats up the surrounding space a bit).</div><div><br></div><div>A commonly used metaphor that may help to understand this is to consider an IO action to be like a recipe like one might find in a cookbook. If `getLine` is the recipe for a particular type of cake then it will be the same recipe every time it is invoked. The actual cake that you produce when you execute the recipe may differ—more or less, depending on how proficient you are at baking—but this does not mean that the recipe itself has changed each time. And so it is with IO: The actions are pure. They are the same every time. The results that they produce when executed may change, but this is not at odds with our claim that the values themselves are pure.</div></div><div dir="ltr"><div><br></div><div>> <span>also, could we say that a function that returns a value of such a type of which no part is a function (for lack of a better definition) is definitely a pure function</span></div><div><span><br></span></div></div><div dir="ltr"><div><span>Yes, and all the other functions are pure too.</span></div><div><br></div><div>[1] Modulo usages of `unsafePerformIO` and friends, but these can and should be dealt with separately.<br></div></div><br><div class="gmail_quote"><div dir="ltr">On Sat, Dec 26, 2015 at 4:09 AM Imants Cekusins <<a href="mailto:imantc@gmail.com" target="_blank">imantc@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">for some practical purposes, would it make sense to forget about<br>
effects and purity and distinguish only between IO and non-IO? It<br>
should be easy enough to tell IO from non-IO, no?<br>
<br>
also, could we say that a function that returns a value of such a type<br>
of which no part is a function (for lack of a better definition) is<br>
definitely a pure function<br>
<br>
?<br>
_______________________________________________<br>
Beginners mailing list<br>
<a href="mailto:Beginners@haskell.org" target="_blank">Beginners@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners</a><br>
</blockquote></div></div>