Let’s run through some simple Boolean expressions and their associated ASTs.
(or #t #f) evaluates to #t.
Similarly, (not #t) is #f, which is fair, after all, something that’s not true has to be false. Play around with these in Racket to get a feel for them, as they can be arbitrarily complex.
Here is the AST for (or (and #t #f) (or #t #f))
Then we get:
What happens if we pass numbers to these operators? In λ calculus and Racket, all numbers are considered true. Note that this might be different from what you may be used to in other programming languages, for example, in some languages, -1 or 0 are considered false.
Let’s run through some examples, they are written in Racket, but are the same in λ calculus.
> (if 1 "first" "second") "first" > (or 1 0) 1 > (or 0 1) 0 > (or 31 #t) 31 > (or #t 31) #t
So what exactly is going on here? If all numbers are considered to be true, shouldn’t or return true? As far as it is concerned, it is returning true, because it is returning a number, so now the question becomes how does it know which number to return? The rule for or is that it returns the first TRUE value it can find, otherwise it returns FALSE. The fact that sometimes that first TRUE value is not a Boolean doesn’t matter, or will happily return whatever it is given.
What about and? It basically does the opposite of or and returns the last TRUE value it can find, otherwise it returns FALSE. Look at these examples:
> (and 3 -1) -1 > (and -1 3) 3 > (and 1 #f) #f > (and #f 2) #f
This means that for and to return TRUE, it must test every value given to it, while for or to return FALSE, it must evaluate everything. You might guess from the way we described these that operators such as or and and can take any number of arguments, just like other prefix operators, and this is exactly true, and we can apply the exact same rules we did when there were two arguments.
What about and? It basically does the opposite of or and returns the last TRUE value it can find, otherwise it returns FALSE. Look at these examples:
> (and 1 2 3 4) 4 > (or 1 2 3 4) 1 > (not 1 2 3 4) not: arity mismatch
Okay, so they don’t all take multiple arguments; specifically, not is only defined for a single argument, and that’s fair enough, given that it simply inverts the truth of what it is given.
We’ve seen strings floating around in some of these examples, typically as return values. However, with Functional Programming languages, whatever one function returns another one could take as a parameter, so we need to understand the implication of strings being passed to Boolean operators too. As with numbers, all strings are true, and the operators all work the same way.
> (and "hello" "goodbye") "goodbye" > (or "hello" "goodbye") "hello"
In the next section we’ll look at how to use these conditionals in functions.