At the level of source code logic it appears to be copying and returning a new data structure. That doesn't mean the compiled, optimized code is performing all the copies that the the program appears to be doing.
Pure FP = don't mutate variables in the program. Of course the actual implementation can reuse memory blocks or else pure FPers would have to keep buying new memory!
x is a bound variable. It doesn't 'vary' in the sense that the value it refers to can be mutated, as in a imperative language, but it varies between calls to the function f.
It is rebound. It is improper to call it a "variable" because in any given lifetime, it's value cannot vary. That's the point. It is possible to create a new binding with the same name, but any code holding on to the old instance keeps the old value. Subtle but important difference.
"Varying, in the context of mathematical variables, does not mean change in the course of time, but rather dependence on the context in which the variable is used."
While I agree with your philosophy of vocabulary here, I've read the Harper article too, it's valuable to state directly that everyone knows there's the _(Programming) article too and is simply disagreeing that its a "good" way to use the term. Anyone who isn't familiar with the distinction in terminology ought to consider what things a programming variable represents that a mathematics variable does not..
"The identifier in computer source code can be bound to a value during run time, and the value of the variable may thus change during the course of program execution. Variables in programming may not directly correspond to the concept of variables in mathematics."
It's wrong that it's "improper" to use the term "variable" for Haskell variables, since it is an established usage. This usage of "variable" occurs in the very first paragraph of Church's first paper on lambda calculus from 1931 in the motivation for the whole project!
That's a rather strange assertion, if you mean "variables" and "values." Math distinguishes between variables and values. Variables have different values. Values can be bound to variables. Sometimes we do math with mostly variables and few values -- that's called algebra.
When combined with lexically scoped closures, if you try to shadow your value bindings in a functional language and expect it to work the same way as mutating a variable does in an imperative language, you're in for a surprise.
Sure, you have to restrict the scope in which rebinding is legal, but I don't see how it's fundamentally any different than the use of a phi-node in SSA form.
val it = 1 : int // a is still bound to 1 as far as f() is concerned
Now in Javascript:
> var a = 1;
undefined
> function f(){return a};
undefined
> f();
1
> a = 2;
2
> f();
2
>
If you bind a val, then you define a function that references that val, then you later shadow the val binding, then call the function again, the function still sees the earlier val binding, because it's a closure of the environment at the point where the function was defined, not at the point where it was called. This is unlike variable assignment in imperative languages.
Pure FP = don't mutate variables in the program. Of course the actual implementation can reuse memory blocks or else pure FPers would have to keep buying new memory!