[Haskell-beginners] explaining effects

Rein Henrichs rein.henrichs at gmail.com
Sat Dec 26 18:59:58 UTC 2015


> 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.

This is actually a bit suspect for ST, since it involves uses of the unsafe
functions mentioned in my footnote. The argument is that these functions
are being used in a provably safe way, but the proof cannot be executed in
Haskell: it must be executed elsewhere and ported into Haskell, but it is
still valid (unless the implementation is incorrect). This is an exemplary
usage of unsafe functions to provide *safe* features where the implementor
has satisfied this proof of safety obligation elsewhere and doesn't require
Haskell's type system to prove it for them; and where they otherwise
wouldn't able to provide this functionality or this performance
optimization or etc.


On Sat, Dec 26, 2015 at 10:53 AM Rein Henrichs <rein.henrichs at gmail.com>
wrote:

> TL;DR: Evaluation is always pure[1]. Execution isn't, but it wasn't
> supposed to be in the first place.
>
> > 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?
>
> There is no need to distinguish between IO and non-IO. Everything is pure,
> including IO.
>
> 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.
>
> 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.
>
> 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).
>
> 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.
>
> > 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
>
> Yes, and all the other functions are pure too.
>
> [1] Modulo usages of `unsafePerformIO` and friends, but these can and
> should be dealt with separately.
>
> On Sat, Dec 26, 2015 at 4:09 AM Imants Cekusins <imantc at gmail.com> wrote:
>
>> for some practical purposes, 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?
>>
>> 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
>>
>> ?
>> _______________________________________________
>> Beginners mailing list
>> Beginners at haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/beginners/attachments/20151226/d9c597fe/attachment.html>


More information about the Beginners mailing list