1

I was reading about "Referential Transparency" that says how to program thinking about purity and determinism. It's said that a function that modifies an outside state is unpure.

But what about a function that only read an outside state (such as reading a global variable), is it unpure too?

4

An expression is referentially transparent if we can replace the expression with its value, without changing the behaviour of the program. Under that definition a function is pure if we can replace any call to that function with its return value.

If a function interacts with an external variable in a way that affects the bheviour of the program then the function is impure – not just writing but also reading, if that variable might be modified elsewhere: it is not external variables that turn a function impure, but external state.

For example, this JavaScript function f is entirely pure, even though it accesses an external variable b:

function makeF(a) {
  var b = 2 * a;
  return function (c) {
    return b + c;
  };
}
var f = makeF(3);

An example of an external variable that might be read and written without turning a function impure would be a cache. The cache doesn't affect the result of a function, it is just an optimization. Here, purity depends on the perspective. A memoized/cached pure function might be impure from the perspective of a compiler writer because it accesses the cache as a side effect. But it is pure from the perspective of a user of the function – and we can still replace a function call expression with its result.

  • 2
    The expression inside the function which interacts with the cache is (probably) impure, but the function viewed as a black box from the outside is pure. It is a matter of scale: Verifying that all state interactions are correct inside a 5 line function is easy, verifying that all state interactions are correct in a 5 million line program is not. – Jörg W Mittag Jul 21 '18 at 14:44
  • amon, I agree with you. If a function depends on something outside that can change the result, no matter if it's reading or writing, it's not pure. But how I can increase the number of pure functions in my code? Would I need, for example, review my code replacing external state with internal arguments? What else? – Isaac Ferreira Jul 22 '18 at 16:07
  • @zaclummys The general approaches are to prefer immutable data structures such as linked lists, prefer recursion over updating variables, and to separate a pure functional core of your application from impure interfaces with the outside world (works great for web servers). But why are you trying to use more pure functions? E.g. if you're using JavaScript the core language simply doesn't lend itself to a pure functional style. Haskell does go down that route, but now simple things like nested record updates foo.bar.baz = 42 are so complicated that there's academic research into workarounds. – amon Jul 22 '18 at 16:27
  • Pure functions would make my code more readable and with fewer bugs, I believe. But I know that won't be possible write 100% pure code. Hence, I will sort them out by pure and impure. – Isaac Ferreira Jul 22 '18 at 17:58
3

Referential Transparency means that you can replace a function application with its result (or more generally, an expression with its evaluation) anywhere and/or everywhere in the program, without changing its result.

Here is an example of a program with a function that only reads but does not modify a global variable:

let global = 0;

function foo(i) {
  return i + global;
}

const one = foo(1);
// foo(1) == 1

global = 100;

const two = foo(1);
// I should be able to replace this with const two = 1, since foo(1) was 1 above

console.log(two);
// 101

This prints 101.

If foo were referentially transparent, I should be able to replace any occurrence of foo(1) with 1. And vice versa, I should be able to replace any occurrence of 1 with foo(1).

Let's try that:

let global = 0;

function foo(i) {
  return i + global;
}

const one = foo(1);

global = 100;

const two = 1;

console.log(two);
// 1
// Oops!

As you can see, replacing foo(1) with its result changes the meaning of the program. Ergo, foo is not referentially transparent.

There is another important lesson here: if global were a constant instead of a variable, then foo would be referentially transparent. foo is not referentially transparent because of some completely different piece of code somewhere else. Side-effects are infectious and can act across large distances!

0

I tend towards yes, because calling the same function twice (with the same arguments) can result in different results. Note that, assuming the function is otherwise pure, it can easily be modified to actually be pure by passing the value of the global variable in as an argument to the function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.