Coding the Liar Paradox

Assaf Rotbard
Riskified Tech

--

As a software developer with a philosophy degree, I often find myself being asked how my degree is relevant to my work. While to me it’s clear that my philosophy studies have been invaluable for my development skills, I find it hard to explain to others. Unlike a computer science graduate whose studies have a very obvious impact on their work, as a philosophy graduate I need to show how dealing with metaphysics, ethics, or logic questions adds value to my day-to-day work as a software developer.

I can try and argue that both fields require analyzing problems, critical thinking, and problem-solving skills, but I think a better approach would be to demonstrate how close these fields are by examining a famous philosophy question. In this article, I will present the classical logic exercise of the Liar Paradox and analyze it using code implementation. By doing this, I hope that I can, on the one hand, get software developers interested in philosophy, and on the other hand, provide a better answer to a question I am often asked.

The Liar Paradox

As a philosophy student, one of the topics that intrigued me the most was paradoxes of self-reference. A paradox of self-reference is a statement that, by referring to itself, causes a paradox — meaning, the conclusion of this statement will go beyond our common beliefs.

A self-reference statement can have a truth value (true or false):

  • This statement has 33 characters (true)
  • This statement is bold (false, but could be true in different circumstances)

There are more complex statements that include self-contradiction, like:

  • “Every rule has an exception”

Let’s examine the above statement: If it’s true that every rule has an exception, including the rule presented in this statement, the exception of this rule states that there is a rule that can’t have an exception. Therefore, this statement contradicts itself and can’t be true. However, the negation of this statement — “there is such a rule that has no exception” is a true statement, since we can show the existence of such a rule. For example — “all even numbers are divisible by 2.”

The most interesting form of self-reference statements, however, is the one that leads to a paradox, and the most famous one is the Liar Paradox. This is one of the paradox’s definitions, as explained in Wikipedia:

A: This statement (A) is false.

If (A) is true, then “This statement is false” is true. Therefore, (A) must be false. The hypothesis that (A) is true leads to the conclusion that (A) is false, a contradiction.

If (A) is false, then “This statement is false” is false. Therefore, (A) must be true. The hypothesis that (A) is false leads to the conclusion that (A) is true, another contradiction. Either way, (A) is both true and false, which is a paradox.

This unique and short statement (A) has very powerful consequences. If A is true it must be false but if it’s false it must be true. In other words, we see that statement (A) can’t have a defined truth value. This is an irregular conclusion that contradicts the fact that all statements must have a truth value. Although it’s a very short argument, I think you will agree that it’s a bit confusing. To make it best understood for software developers, I decided to “translate” the paradox into code. I chose to implement the Paradox with Ruby as a boolean function in hope to catch the essence of statement (A). We need to pass a boolean parameter to the function to indicate if it’s TRUE or FALSE — the same practice we have in investigating statement (A).

The output of running this code would be:

this_sentence_is_false is a -true- statementthis_sentence_is_false is a -false- statementthis_sentence_is_false is a -true- statementthis_sentence_is_false is a -false- statementthis_sentence_is_false is a -true- statementthis_sentence_is_false is a -false- statementthis_sentence_is_false is a -true- statement...SystemStackError (stack level too deep)

As you might have guessed, this function ends up with StackOverflowError. While it wasn’t clear at first sight that statement (A) will lead us to a circular debate of truth values, I’m sure that you could understand from a short examination of this_statement_is_false that it will lead to an infinite recursion — this will be best illustrated in the following diagram:

At this point, I hope that bringing the Paradox into the realm of code helped you to understand the idea behind the Liar Paradox. However, does it really demonstrate the essence of the paradox? Did the transfer of the statement into code help us understand the problematic conclusion that statement (A) does not have any truth value? Probably not — yet.

Solving the Paradox

When philosophers deal with the Liar Paradox they will try to “solve” it. Accepting its conclusion will contradict the “law of excluded middle” which is one of the fundamental rules of thought. This law states that for every proposition, either the proposition or its negation must be TRUE. Just try to think about any logic exercise: Would you be able to prove anything without this rule? Therefore, many philosophers have struggled with solving the Liar Paradox. While there were plenty of attempts to solve the Liar Paradox with different conclusions, I won’t expand on those solutions (though I’m inviting you to explore them yourselves). Instead, I will present one attempt for solving the paradox and demonstrate how implementing the paradox with code corresponds to this solution.

As we’ve already seen, by implementing the Liar Paradox we have discovered that the argument has some aspect of infinite recursion. I believe a similar sense is reflected in one of the famous solutions to this paradox, suggested by Saul Kripke. Kripke suggests that we should distinguish between two types of statements — “grounded” and “ungrounded.” A grounded statement is a statement that will eventually argue something about the world that can be proved. Therefore, the truth value of that statement will be deducted from the truth of that fact about the world.

For example, the following statement (B) is grounded.

B. The next statement is a lie

B1. The next statement is a lie

B2. The next statement is a lie

B4. Today is Friday

As we can see, statement (B) has a truth value that will be set (eventually) from the fact that today is or isn’t Friday. Although the statement “the next statement is a lie” has no truth value by itself, when it is part of a series of statements like the one presented here it could be grounded if, at some point, the series of statements is fixed on a claim about the world. So, if today is Friday then (B2) is false, (B1) is true, and (B) is false. But on any other day, (B) is true! Although the truth value of (B) is changeable, it is grounded and no matter what the day is today, statement (B) has a truth value.

In contrast, the next statement © is ungrounded:

C. (C) is true

Is (C)true? Well, if (C) is true then (C) is true. But (C) is true if (C) is true. Can you see where I’m going with this? Although (C) is not paradoxical, it can’t produce a truth value. In that sense, (C) is an ungrounded statement since it has nothing to say about the world we can use to determine its truth value.

Let’s go back to the code. As a software developer, you’re probably familiar with using recursion to solve problems. The main challenge when writing a recursion is usually to define a “stop condition”: A condition that allows the function to go toward a solution but also promises the code will stop and will not become a vicious circle. This is exactly what we lack before when implementing the Liar Paradox. The recursive function this_statement_is_false has no valid stop condition. The idea of a valid stop condition is very similar to the idea of “grounded” statements.

I want to emphasize this idea by implementing the last two statements. A grounded statement could be transformed into the below function. I added a made-up stop condition with a depth parameter to simulate example (B) when we have a series of four statements:

This will yield the following output on Friday:

This statement is groundedthe truth value of statement at depth 4  is falsethe truth value of statement at depth 3  is truethe truth value of statement at depth 2  is falsethe truth value of statement at depth 1  is true

While an ungrounded statement will transform into something like this:

This will yield:

Am I true?Am I true?Am I true?Am I true?Am I true?...SystemStackError (stack level too deep)

As we can see, while the grounded_statement has a valid stop condition (the number of iterations) and it will always return a boolean response (equivalent to a truth value), the output of the this_is_true statement can’t produce any response and will raise a StackOverFlowError. This is, of course, very similar to the output of the Liar Paradox function we saw before. In both cases, the implementation of the statement is a recursive function without a valid stop condition.

For the grounded statement (B), we could “manually” set the (B3) “Today is Friday” statement so that it will say something about the world and by that enable (B) to achieve its truth value. The Liar Paradox, however, is a statement that is “too focused” on itself, and even when it’s trying to say something about the world (“everything I say is false”) it will always fail to ground itself and will result in a pursuit that will never end (at least until the stack is exceeded).

Conclusion

After introducing and implementing the Liar Paradox with code, we can see the similarities between the paradox and the ungrounded sentences presented within this article. I won’t argue that this solves the paradox, but I think we can conclude that this approach strengthens the idea that the Liar Paradox shares some common properties with ungrounded statements. This, I hope, helps to understand the paradox and what a possible solution could look like.

More than that, I hope I have been able to demonstrate a connection between philosophy and software development and spark an interest in philosophy for software developers who are unfamiliar with the field in general and with the Liar Paradox in particular.

--

--