# Logical Operators: `not/and/or`¶

Often conditional switches are more complex than a simple true/false decision. Sometimes it is more convenient to ask if something is false than if it's true, and regularly multiple conditions have to be considered in relation. To achieve this Scheme offers the procedures `not`, `and` and `or`.

### `not`¶

`not` is basically the inversion of a test: it returns `#t` if the expression it tests evaluates to `#f` and to `#f` in all other cases.

```guile> (not #f)
#t

guile> (not #t)
#f

guile> (not '(1 2 3))
#f

guile> (not (< 2 1))
#t
```

The first two expressions are clear, `not` simply inverts the boolean literals. The third example shows that any object has a “true value” and is inverted to `#f`. The final example demonstrates that the value passed to `not` can (of course) be a complete expression which in this case evaluates to `#f`, which is then inverted by the `not`.

### `and`¶

`and` takes any number of subexpressions and evaluates them one after another until any one evaluates to `#f`. In this case the `and` expression evaluates to `#f` as well. If all subexpressions evaluate to a true value the `and` returns the value of the last subexpression. This is an important point: `and` does not evaluate to `#t` or `#f` as one might expect, instead it evaluates to `#f` or an arbitrary value. You have to take that into account when you need to use that value:

```guile>
(and
#t
(> 2 1)
(odd? 2)
"Hi")
#f
```

This expression holds four subexpressions that are tested sequentially:

• `#t` is obviously a true value
• `(> 2 1)` evaluates to `#t` as 2 is greater than 1
• `(odd? 2)` evaluates to `#f` as 2 is not an odd number
• "Hi" would be considered a true value, but it isn't tested anymore because `and` has exited already upon the previous subexpression.
```guile>
(and
'(1 . 2)
(list? '())
#t
'(1 2 3))
(1 2 3)
```

In this `and` expression all subexpressions have true values, therefore the whole expression evaluates to the value of the last subexpression, the list `(1 2 3)`. So this is where you must not expect `#t` but rather any true value.

### `or`¶

`or` behaves very similarly to `and`, except that it returns a subexpression's value as soon as that returns a true value. Only if none of the subexpressions return true values the `or` expression returns `#f`. And as with `and` you have to expect “a true value” and not `#t` for the successful subexpression.

In the case of `or` this can be used very straightforwardly to provide fallthrough values: check for a number of tests, and if all fail return the fallback value as the last subexpression. For example we can easily rewrite the test from the previous chapter using `or`:

```colors =
#`((col-red . ,red)
(col-blue . ,blue)
(col-yellow . ,yellow))

#(display
(or
(assq 'col-lime colors)
(assq 'col-darkblue colors)
(assq 'col-red colors)
(cons 'black black)))
```

## Nesting of Logical expressions¶

When more than one condition have to be nested dealing with “operator precedence” is a confusing issue in many languages: which conditionals are evaluated first, do we therefore have to group them with brackets, etc.? Scheme's approach to this topic is very straightforward, and once you get the fundamental idea it is no magic anymore: Each conditional expression tests one single value, and that value can be the result of another logic expression. Period. From there you can create arbitrary levels of nesting.

What does the expression `(not (and #t #f))` return and why? We have a `not` which will invert the boolean state of the value it is applied to. That value is the expression `(and #t #f)`, which will evaluate to `#f`. So the first evaluation step is to evaluate the inner expression, which leads to `(not #f)`, which eventually results in `#t`.

Let's inspect a more complex expression:

```(or (not (> 2 1)) (and #t '() (> 4 5)) "Hehe")
```

This is an `or` expression with three subexpressions: `(not (> 2 1))`, `(and #t '() (> 4 5))` and `"Hehe"`. `or` will evaluate each of these subexpressions from left to right, and once any subexpression eavaluates to anything other than `#f` it will return that subexpression's value. So let's retrace that one by one:

```(not (> 2 1))
(not    #t  )
#f
```

The first subexpression evaluates to `#f` so we have to continue. The second subexpression is an `and` expression which itself has multiple subexpressions: `#t`, `'()` and `(> 4 5)`:

```#t
#t ; a true value

'()
() ; a true value

(> 4 5)
#f
```

The first two subexpressions of the `and` have true values, but the last one is `#f`, therefore the whole `and` subexpression evaluates to `#f`, and we have to continue with the last subexpression, `"Hehe"`. This subexpression has a true value, so finally our `or` returns that one and can be considered successful.

As a conclusion, nested logical expressions in Scheme are just like any other nested expressions: they have to be evaluated one by one, from inside to outside and in the case of `and` and `or` from left to right, and so everything can be resolved unambiguously.

Last update: January 31, 2020