Search code examples
javascriptfunctionfunctional-programming

How to correctly identify pure functions in functional programming?


Is this function pure or impure?

function greet(name) {
    return "Hi I'm " + name;
}

The property of pure function is that it has no side effects and always returns the same output for the same input.

Here, it produces side effects (returning a string). The string concatenation, "Hi, I'm " + name, introduces a dependency on external state. Impurity is made from "Hi, I'm " .

We can rewrite the code below to make it pure.

//pure function
function pureGreet(greeting, name) {
    return greeting + name;
}

//console output
const hiGreeting     = "Hi, I'm ";

const actualGreeting = pureGreet(hiGreeting, "John");

console.log(actualGreeting);

Is this explanation correct?


Solution

  • No, that explanation isn't correct.

    Here, it produces side effects (returning a string)

    No, returning a value is not a side effect. That's what functions do.

    The string "Hi I'm " is a constant, so that doesn't change the characteristics of what constitutes referential transparency:

    • Does it always return the same output given the same input? Yes.
    • Does it have any side effects? No.

    Therefore it's a pure function.

    Constants are just constants. You could imagine another function that always adds 2 to its input:

    function add2(i) {
        return 2 + i;
    }
    

    This is pure as well, since 2 is a constant. add2(2) always returns 4, and add2(3) always returns 5, and so on.

    The string concatenation, "Hi, I'm " + name, introduces a dependency on external state

    The string "Hi, I'm " is actually not external to the function body, but an implementation detail.

    That said, depending on external state is not in itself cause for impurity, as long as that external state is immutable. That's what closures do.


    There is, by the way, a subtle distinction between purity and referential transparency that Tyson Williams has pointed out to me. It mostly becomes important in languages like Haskell, but the bottom line is that you can have referentially transparent functions with 'impure implementations'. The F# base library does this a lot.

    If you're really interested, I don't know of a better place to link to than the long thread where Tyson Williams originally made me aware of that distinction: https://blog.ploeh.dk/2020/02/24/discerning-and-maintaining-purity/#d28c24c07228400f9ed141f97b5c72b5