Haskell/Truth values

Equality and other comparisons
In the last chapter, we used the equals sign to define variables and functions in Haskell as in the following code:

That means that the evaluation of the program replaces all occurrences of  with   (within the scope of the definition). Similarly, evaluating the code

replaces all occurrences of  followed by a number ( 's argument) with that number plus three.

Mathematics also uses the equals sign in an important and subtly different way. For instance, consider this simple problem:

Our interest here isn't about representing the value $$5$$ as $$x+3$$, or vice-versa. Instead, we read the $$x+3=5$$ equation as a proposition that some number $$x$$ gives 5 as result when added to 3. Solving the equation means finding which, if any, values of $$x$$ make that proposition true. In this example, elementary algebra tells us that $$x=2$$ (i.e. 2 is the number that will make the equation true, giving $$2+3=5$$).

Comparing values to see if they are equal is also useful in programming. In Haskell, such tests look just like an equation. Since the equals sign is already used for defining things, Haskell uses a double equals sign,  instead. Enter our proposition above in GHCi:

GHCi returns "True" because $$2 + 3$$ is equal to 5. What if we use an equation that is not true?

Nice and coherent. Next, we will use our own functions in these tests. Let's try the function  we mentioned at the start of the chapter:

This works as expected because  evaluates to.

We can also compare two numerical values to see which one is larger. Haskell provides a number of tests including:  (less than),   (greater than),   (less than or equal to) and    (greater than or equal to). These tests work comparably to  (equal to). For example, we could use  alongside the   function from the previous module to see whether a circle of a certain radius would have an area smaller than some value.

Boolean values
What is actually going on when GHCi determines whether these arithmetical propositions are true or false? Consider a different but related issue. If we enter an arithmetical expression in GHCi the expression gets evaluated, and the resulting numerical value is displayed on the screen:

If we replace the arithmetical expression with an equality comparison, something similar seems to happen:

Whereas the "4" returned earlier is a number which represents some kind of count, quantity, etc., "True" is a value that stands for the truth of a proposition. Such values are called truth values, or boolean values. Naturally, only two possible boolean values exist:  and.

Introduction to types
and  are real values, not just an analogy. Boolean values have the same status as numerical values in Haskell, and you can manipulate them in similar ways. One trivial example:

is indeed equal to, and   is not equal to. Now: can you answer whether  is equal to  ?

Error! The question just does not make sense. We cannot compare a number with a non-number or a boolean with a non-boolean. Haskell incorporates that notion, and the ugly error message complains about this. Ignoring much of the clutter, the message says that there was a number on the left side of the , and so some kind of number was expected on the right side; however, a boolean value  is not a number, and so the equality test failed.

So, values have types, and these types define limits to what we can or cannot do with the values. and  are values of type. The  is complicated because there are many different types of numbers, so we will defer that explanation until later. Overall, types provide great power because they regulate the behavior of values with rules that make sense, making it easier to write programs that work correctly. We will come back to the topic of types many times as they are very important to Haskell.

Infix operators
An equality test like  is an expression just like  ; it evaluates to a value in pretty much the same way. The ugly error message we got on the previous example even says so:

When we type  in the prompt and GHCi "answers" , it is simply evaluating an expression. In fact,  is itself a function which takes two arguments (which are the left side and the right side of the equality test), but the syntax is notable: Haskell allows two-argument functions to be written as infix operators placed between their arguments. When the function name uses only non-alphanumeric characters, this infix approach is the common use case. If you wish to use such a function in the "standard" way (writing the function name before the arguments, as a prefix operator) the function name must be enclosed in parentheses. So the following expressions are completely equivalent:

Thus, we see how  works as a function similarly to   from the previous module. The same considerations apply to the other relational operators we mentioned and to the arithmetical operators (,  , etc.) – all are functions that take two arguments and are normally written as infix operators.

In general, we can say that tangible things in Haskell are either values or functions.

Boolean operations
Haskell provides three basic functions for further manipulation of truth values as in logic propositions:


 * performs the and operation. Given two boolean values, it evaluates to  if both the first and the second are , and to   otherwise.


 * performs the or operation. Given two boolean values, it evaluates to  if at least one of them is   and to   otherwise.


 * performs the negation of a boolean value; that is, it converts  to   and vice-versa.

Haskell libraries already include the relational operator function  for not equal to, but we could easily implement it ourselves as:

Note that we can write operators infix even when defining them. Completely new operators can also be created out of ASCII symbols (which means mostly the common symbols used on a keyboard).

Guards
Haskell programs often use boolean operators in convenient and abbreviated syntax. When the same logic is written in alternative styles, we call this syntactic sugar because it sweetens the code from the human perspective. We'll start with guards, a feature that relies on boolean values and allows us to write simple but powerful functions.

Let's implement the absolute value function. The absolute value of a real number is the number with its sign discarded; so if the number is negative (that is, smaller than zero) the sign is inverted; otherwise it remains unchanged. We could write the definition as:

$$|x| = \begin{cases} x, & \mbox{if } x \ge 0  \\ -x,  & \mbox{if } x < 0. \end{cases} $$

Here, the actual expression to be used for calculating $$|x|$$ depends on a set of propositions made about $$x$$. If $$x \ge 0$$ is true, then we use the first expression, but if $$x < 0$$ is the case, then we use the second expression instead. To express this decision process in Haskell using guards, the implementation could look like this:

Remarkably, the above code is about as readable as the corresponding mathematical definition. Let us dissect the components of the definition:


 * We start just like a normal function definition, providing a name for the function,, and saying it will take a single argument, which we will name.


 * Instead of just following with the  and the right-hand side of the definition, we enter the two alternatives placed below on separate lines. These alternatives are the guards proper. Note that the whitespace (the indentation of the second and third lines) is not just for aesthetic reasons; it is necessary for the code to be parsed correctly.


 * Each of the guards begins with a pipe character, . After the pipe, we put an expression which evaluates to a boolean (also called a boolean condition or a predicate), which is followed by the rest of the definition. The function only uses the equals sign and the right-hand side from a line if the predicate evaluates to.


 * The  case is used when none of the preceding predicates evaluate to  . In this case, if   is not smaller than zero, it must be greater than or equal to zero, so the final predicate could have just as easily been  ; but   works just as well.

and Guards
clauses work well along with guards. For instance, consider a function which computes the number of (real) solutions for a quadratic equation, $$ax^2 + bx + c = 0$$:

The  definition is within the scope of all of the guards, sparing us from repeating the expression for.