Functional Programming 101 Series

The Concept of Referential Transparency

By ANTHONY KHONG

In the previous part, we made the point that global mutations can be a source of confusion, as it creates “moving parts”. Before we move on to the benefits of working with pure functions, it is important to first understand the concept of referential transparency.

An expression is called referentially transparent if it can be replaced with its corresponding value without changing the program’s behaviour. This is especially relevant to FP, because purity implies referential transparency. Suppose we only work with pure functions:

>>> def g(xs):
...     return xs[::-1]
...
>>> xs = [1, 2, 3]
...
>>> g(xs) # Out: [3, 2, 1]

Since g is a pure function, calling it results in a referentially transparent expression. In particular, g(xs) can always be replaced with g([1, 2, 3]), or [3, 2, 1] anywhere in the codebase without changing the behaviour of the programme. Compare this to when working with impure functions:

>>> def g(xs):
...     xs.reverse()
...     return xs
...
>>> xs = [1, 2, 3]
...
>>> g(xs) # Out: ???

The value of xs may initially be [1, 2, 3], but the same variable may hold different values at a different time, because it may have been mutated elsewhere in the codebase. Therefore, we cannot freely replace g(xs) with, say, g([1, 2, 3]) without changing the behaviour of the programme! Whether or not it changes the behaviour would depend on the context of the programme. In short, you cannot examine g(xs) separately to other parts of the programme!

One way to think about referential transparency is tying down identity and value. With impure functions, an identity, say id(xs), can have many values over time. With pure functions, an identity is tied to its value over the span of the programme.

Diagram about Mutation Identity and Value

It is common to hear proponents of FP to say, “FP makes it easy for you to reason about your code.” It may sound like a cryptic thing to say! However, in light of our discussion on referential transparency, what they really mean is that:

  • You can examine a piece of code in isolation without worrying about the larger context of the programme
  • Values are tied to its identity, so that there are no moving parts!

RECENT POSTS