Hacker News new | ask | show | jobs
by mthq 3554 days ago
The author uses the definition that a pure function must return identical outputs on identical inputs. I actually think a better definition is that the output of a function cannot depend on anything but it's inputs. If we use that definition then the first example he gives where the `sum` function violates pureness is actually not a violation. This is also justified by interpreting a `.valueOf = Math.random` field as a random variable, making the procedure `sum` a map from a random variable to a random variable.
3 comments

I think it's commonly agreed that pure functions depend only on their inputs AND cannot have side effects. So when introducing 'Math.random' the function would be impure as it has side effects.
Is it then the variable (or the variable accessor) that is impure, or the function that is impure?
The variable accessor is a function of type Variable -> Field, which the function sum is calling. Because of that, the function sum is impure, as it's calling an impure function. I would argue that the object is just a wrapper around a function, and in essence making the sum function implicitly higher order, as you're passing it a function to retrieve a value, rather than an actual value.
Math.random doesn't necessarily have side affects. If it's storing a seed value, and incrementing that each time; then yes it stores mutable state which is a side affect because future invocations of that function will then depend upon that pre-existing state.

If however Math.random is passively listening for background radiation through some sensor perhaps then it doesn't really have side affects does it? Nor does it have mutable state, for that matter.

But it would still be impure according the true definition of what is a pure function, I believe.

I thought it was a bit pedantic as well, at first. But looking at Haskell, I can see why the author made this point. Haskell functions won't accept random values as input, since they're monadic values.
Are there two identical inputs to Math.random that yield different results? If the answer to that question is yes, the function isn't pure.
Replace Math.random with this, then:

    ((j) => () => j++)(0)
That's what I thought. It boils down to the question of whether:

    f => f()
is a pure function? If so, then so is the author's example. If not, then I don't see how any JS function that takes an argument (and evaluates it) can be pure. Under that definition, I'm not sure it makes sense to talk about.
Is Haskell's `(++) :: [a] -> [a] -> [a]` pure? What if I pass `unsafePerformIO` to it?

For theoretical purposes it might make sense to say pure functions cannot call impure functions, but I think a more practical definition includes functions that are provided as arguments.

Haven't the faintest. I don't speak Haskell, 's why I asked.

I'd thought pureness was a property of function definitions, irrespective of what they get passed, but living in Javascript land I've never had occasion to be concerned with the distinction. I kind of suspect it's not really something that's useful to talk about.

Not asking you directly, I agree with you and was trying to rephrase the notion.
If you introduce unsafe into a program, it is not pure. You can run a linter or something to check if your program uses unsafe anywhere.

Purity is a spectrum, not a binary, The more impurities you add, the more likely your program will not behave reasonably (as in, not in accordance with the simple logical rules of referential transparency).

> If not, then I don't see how any JS function that takes an argument (and evaluates it) can be pure.

A JS function could take an argument, use it but not evaluate it (or not evaluate it in all cases). `typeof` doesn't evaluate its argument for instance.

Certainly it could. I don't know what that has to do with my comment though.
The definition of a pure function is pretty well defined https://en.wikipedia.org/wiki/Pure_function. Math.random depends on hidden state, so (generally) any function using it isn't pure. This doesn't matter much in a language like Javascript, but other languages depend upon this definition (like the lazy function evaluation in Haskell).
Is that definition of pure closer to mthq's definition or the one in the article? I'm not sure.

It says "same argument value(s)", but how does that apply when the argument is a function? The article seems to be saying that if the same argument is passed in every time, then the function is only pure if it returns the same value every time, regardless of whether the argument is a pure function or not.

A pure function can't call a non pure function. So you can pass in a non pure function so long as you don't call it.
It's not so well-defined. In particular, "side effect" is hard to pin down. For instance, a good definition ought to consider potential non-termination a side effect. In that way, many functions are impure.
It's a mathematical definition, of course it will break down a bit when you introduce it into the real world. I guess a more pragmatic definition would be "The ability for a runtime to delay, or repeat the execution of a function (with its arguments), and always get the same result".
I mean that it's not even so well defined mathematically. Starting from a weak place and then moving it to the "real world" makes things quite tricky.
> I mean that it's not even so well defined mathematically.

Which part of it isn't? The distinction between "potentially non-terminating" and its negation is exactly the distinction between partial and total functions.

The definition of pure function (or, dually, side effect) is difficult to pin down. I've heard a number of definitions, but the best ones are far more technical than you'd see in casual conversation and the casual ones often admit holes.
Pretty well defined?

> This article needs additional citations for verification ... (July 2014)