Python-based monads essay part 2

Chris Angelico rosuav at gmail.com
Wed Oct 19 13:57:25 EDT 2016


On Thu, Oct 20, 2016 at 3:51 AM, Marko Rauhamaa <marko at pacujo.net> wrote:
> Chris Angelico <rosuav at gmail.com>:
>> Okay. Now let's suppose that, instead of "73" in the first step, you
>> have "ask the user for an integer". Are you allowed to eliminate this
>> prompt, since the result of it cannot possibly affect anything? And if
>> not, why not?
>
> I would guess yes; that's how Python works as well:
>
>     >>> 7 or input()
>     7
>

That's not quite the same. That's equivalent to:

if 7:
    7
else:
    input()

Short-circuiting depends only on what's known *prior* to that
evaluation. Dead code elimination removes the notion of time:

int(input("Enter something:")) * 0 + 5

This can simply return 5, because (barring an exception being thrown)
the value entered cannot affect the result. Python does not do this.
And any system that has optimization flags (PostgreSQL, Pike, etc),
this would be marked "has side effects", and therefore is not
considered dead code. But if you (maybe mistakenly) mark input() as a
pure function, then yes, this could indeed be optimized out.

> However, if we think of the I/O interaction (aka *the process*) to be
> the return value of a function, every bead in the I/O chain counts.

And that's what I mean about making function purity meaningless. Here,
look - this is a pure function!

magic_numbers = [1, 2, 4, 8]
def do_magic(x):
    magic_numbers[x % 4] += x / 4
    return magic_numbers[(x + 1) % 4]

Since the previous state of magic_numbers can be considered an input,
and the new state can be considered an output, this is a pure
function! Right?

>> If you consider that the world changes state as a result of asking the
>> user for input, then you've just eliminated all notion of functional
>> purity.
>
> Not necessarily. Nothing changes the world. Rather you have different
> worlds: the world of the past and the world of the future. The world of
> the past is in the past of the world of the future:
>
>     def print(world, text, cont):
>         return cont(World(past=world, offset=text))
>
>     def print_x_then_y(world, x, y, cont):
>         return print(world, x, lambda world2: print(world2, y, cont))
>
>> You have side effects, plain and simple, and you're using imperative
>> code.
>
> Technically, no. Thought-model-wise, yes.

Technical means nothing if you're destroying the meaning of functional
purity in order to squeeze I/O into it.

> My example above is purely functional as:
>
>  * Every object is immutable.
>
>  * The order of evaluation does not change the end result.
>
> The end result is an ordered sequence of events. The topological order
> is a causal order (you need the past world to construct the future
> world), and causal order generates a temporal order.

Yeah, nice. You just made a mutable object with significant order of
evaluation and then added enough external information to it that you
can pretend it's immutable and can be evaluated in any order. I could
make that same transformation with literally any function, simply by
taking "the world" as an input and an output. It makes the entire
concept utterly meaningless.

ChrisA



More information about the Python-list mailing list