## Conditionals

In the module `tut13.lfe`

, we saw our first conditional, the `(if ...)`

form. We're going to spend the rest of this section discussing `if`

, `cond`

, `case`

, as well as the use of guards and pattern matching to form conditional code branches.

### The `if`

Form

In the previous section, we wrote the function `find-max-min/3`

to work out the maximum and minimum temperature. This work was delegated to two helper functions:

`compare-max/2`

`compare-min/2`

In both of those functions, we introduced the new `if`

form. If works as follows:

```
(if <predicate>
<expression1>
<expression2>)
```

where `<expression1>`

is executed if `<predicate>`

evaluates to `true`

and `<expression2>`

is executed if `<predicate>`

evaluates to `false`

. If you have used other programming languages, then this will be quite familiar to you. If you have not, if should remind you a bit of the logic we looked at when discussing guards.

We can see it in action with the following LFE session in the REPL:

```
lfe> (if (=:= 1 1) "They are equal!" "They are *not* equal!")
"They are equal!"
lfe> (if (=:= 2 1) "They are equal!" "They are *not* equal!")
"They are *not* equal!"
```

Or -- you will be more familiar with this -- our code from the last section:

```
(if (< temp1 temp2)
city1
city2)
```

where, if `temp1`

is less than `temp2`

, the value stored in `city1`

is returned.

So the `if`

form works for two conditions. What about 3? 10? 100? Well, for the situations were we want to check multiple conditions, we'll need the `cond`

form.

### The `cond`

Form

```
(cond (<predicate1> <expression1>)
(<predicate2> <expression2>)
(<predicate3> <expression3>)
...
(<predicaten> <expressionn>))
```

A given expression is only executed if its accompanying predicate evaluates to `true`

. The `cond`

returns the value of the expression for the first predicate that evaluates to `true`

. Using `cond`

, our temperature test would look like this:

```
(cond ((< temp1 temp2) city1)
((>= temp1 temp2) city2))
```

Here's an example which takes advantage of `cond`

supporting more than two logic branches:

```
(cond ((> x 0) x)
((=:= x 0) 0)
((< x 0) (- x)))
```

Note that each predicate is an expression with it's own parentheses around it; on its left is the opening parenthesis for that particular branch of the `cond`

.

Often times when using `cond`

one needs a "default" or "fall-through" option to be used when no other condition is met. Since it's the last one, and we need it to evaluate to `true`

we simply set the last condition to `true`

when we need a default. Here's a rather silly example:

```
(cond ((lists:member x '(1 2 3)) "First three")
((=:= x 4) "Is four")
((>= x 5) "More than four")
('true "You chose poorly"))
```

Any number that is negative will be caught by the last condition.

In case you're wondering, yes: `cond`

works with patterns as well. Let's take a look.

### The Extended `cond`

Form

When we talked about `cond`

above, we only discussed the form as any Lisper would be familiar. However, LFE has extended `cond`

with additional capabilities provided via pattern matching. LFE's `cond`

has the following general form when this is taken into consideration:

```
(cond (<cond-clause1>)
(<cond-clause2>)
(<cond-clause3>)
...
(<cond-clausen>))
```

where each `<cond-clause>`

could be either as it is in the regular `cond`

, `<predicate> <expression>`

or it could be `(?= <pattern> [<guard>] <expression>)`

-- the latter being the extended form (with an optional guard). When using the extended form, instead of evaluating a predicate for its Boolean result, the data passed to the `cond`

is matched against the defined patterns: if the pattern match succeeds, then the associated expression is evaluated. Here's an example:

```
(cond ((?= (cons head '()) x)
"Only one element")
((?= (list 1 2) x)
"Two element list")
((?= (list a _) (when (is_atom a)) x)
"List starts with an atom")
((?= (cons _ (cons a _)) (when (is_tuple a)) x)
"Second element is a tuple")
('true "Anything goes"))
```

That form is not that often used, but it can be very practical.

### The `case`

Form

The `case`

form is useful for situations where you want to check for multiple possible values of the same expression. Without guards, the general form for `case`

is the following:

```
(case <expression>
(<pattern1> <expression1>)
(<pattern2> <expression2>)
...
(<patternn> <expressionn>))
```

So we could rewrite the code for the non-extended `cond`

above with the following `case`

:

```
(case x
((cons head '())
"Only one element")
((list 1 2)
"Two element list")
((list 'a _)
"List starts with 'a'")
(_ "Anything goes"))
```

The following will happen with the `case`

defined above:

- Any 1-element list will be matched by the first clause.
- A 2-element list of
`1`

and`2`

(in that order) will match the second clause. - Any list whose first element is the atom
`a`

will match the third clause. - Anything
*not*matching the first three clauses will be matched by the fourth.

With guards, the case has the following general form:

```
(case <expression>
(<pattern1> [<guard1>] <expression1>)
(<pattern2> [<guard2>] <expression2>)
...
(<patternn> [<guardn>] <expressionn>))
```

Let's update the previous example with a couple of guards:

```
(case x
((cons head '())
"Only one element")
((list 1 2)
"Two element list")
((list a _) (when (is_atom a))
"List starts with an atom")
((cons _ (cons a _)) (when (is_tuple a))
"Second element is a tuple")
(_ "Anything goes"))
```

This changes the logic of the previous example in the following ways:

- Any list whose first element is an atom will match the third clause.
- Any list whose second element is a tuple will match the fourth clause.
- Anything
*not*matching the first four clauses will be matched by the fifth.

### Function Heads as Conditionals

Another very common way to express conditional logic in LFE is through the use of pattern matching in function heads. This has the capacity to make code *very* concise while also remaining clear to read -- thus its prevalent use.

As we've seen, a regular LFE function takes the following form (where the arguments are optional):

```
(defun <function-name> ([<arg1> ... <argn>])
<body>)
```

When pattern matching in the function head, the form is as follows:

```
(defun <function-name>
((<pattern1>) [<guard1>]
<body1>)
((<pattern2>) [<guard2>]
<body2>)
...
((<patternn>) [<guardn>]
<bodyn>))
```

Note that simple patterns with no expressions are just regular function arguments. In other words `<pattern1>`

, `<pattern2>`

, etc., may be either a full pattern or they may be simple function arguments. The guards are optional.

Let's try this out by rewriting the silly `case`

example above to use a function with pattern-matching in the function heads:

```
(defun check-val
(((cons head '()))
"Only one element")
(((list 1 2))
"Two element list")
(((list a _)) (when (is_atom a))
"List starts with an atom")
(((cons _ (cons a _))) (when (is_tuple a))
"Second element is a tuple")
((_) "Anything goes"))
```

If you run that in the REPL, you can test it out with the following:

```
lfe> (check-val '(1))
"Only one element"
lfe> (check-val '(a 1))
"List starts with an atom"
lfe> (check-val '(1 #(b 2)))
"Second element is a tuple"
lfe> (check-val 42)
"Anything goes"
```

And there you have LFE function definitions with much of the power of `if`

, `cond`

, and `case`

!

Let's use some of these forms in actual code now ...

### Example: Inches and Centimetres

[forthcoming]

[tutorial #14]

### Example: Leap Years

[forthcoming]

[tutorial #15]