Reputation: 23522
I'm confused about the nature of functional programming. It is mentioned higher order functions is one of the key concepts, which enables closures and techniques like partial application, i.e. capturing a state or a strategy alongside with a function to be returned.
Yet, another key concepts are pure functions and immutable state. In other words functions wouldn't have side effects or read an external state. They should always return a same result with same parameters.
This seems contradictory with the concept of higher order function, where a function indeed has an access to the state encapsulated by a closure. Of course this doesn't mean function has to mutate the state, but at least the state affects it's behavior.
In other words, same function may return different result at subsequent executions of program. Or have I misunderstood, what the same means as a concept? What I think of is a function of a same name and a body, closure or not. After all, we are talking about mathematical like functions, not a methods of an unique entities. Should I regard functions returned by a higher order function as a different functions, not just referential, but as a definition?
Upvotes: 0
Views: 362
Reputation: 48775
It may not return different result at subsequent executions of program.
function adder(init) {
return (arg) => init + arg;
}
This returns a function. It returns a different function every time, but with the same argument it returns a function that does exactly the same as the previous with the same argument. That makes this pure.
const add10 = adder(10);
const add20 = adder(29);
add10
and add20
are different functions. They run the same code, but in different closures. Both of them are pure since their return value is only dependent on their input.
Closures that mutate are usually easy to see from the code, but globals that are mutated are more difficult. I have had several occasions where Object
has been mutated when loading a library and not always in such way that the result before and after were the same. A functions purity relies on the free variables and global variables are the most vulnerable of free variables.
Upvotes: 4
Reputation: 13115
From Wikipedia:
In computer programming, a function may be considered a pure function if both of the following statements about the function hold:
The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change while program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices (usually—see below).
Evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices (usually—see below).
So purity is defined by behavior of function, and if the behavior of function is such that the outcome remains same even if it depends on some encapsulated internal state, then the function will be pure.
This function is not pure because its return value (which happens to be a function) differs across identical invocations:
function x() { // Not Pure because return value depends on external effect.
const x = Math.random();
return () => x; // Pure
}
Similarly:
function x() {
let x = 0
return {
fn1(y) { // Not pure
x = x + y // side effect which is observable through fn2
return x
},
fn2() { // Not pure because outcome depends on external environment besides arguments
return x // x is exposed to outside world through fn1
}
}
}
Thus, impurity is contagious. An impure function exposing state to mutations from outside world makes any other functions depending on the same state impure.
In contrast, the following is pure (assuming expensiveComputation function is pure):
function x() {
let x;
return () => {
x = x || expensiveComputation() // side effect is not observable/exposed to outside world
return x
}
}
And so is this one:
function fn(x) { // Pure
return {
next() {
return x + 1;
}
prev() {
return x - 1;
}
}
}
y = fn(x)
y.next() // Pure
y.prev() // Pure
Upvotes: 1