Tuomas Toivonen
Tuomas Toivonen

Reputation: 23522

Functional programming and closures / partial application

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

Answers (2)

Sylwester
Sylwester

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

lorefnon
lorefnon

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

Related Questions