11.4.5 The cond* macro

You can use the cond* macro as an alternative to pcase if you find pcase’s syntax too cryptic. In addition, cond* offers some new forms of control flow that aren’t related to being an alternative to pcase.

Macro: cond* &rest clauses

The cond* macro is an extended form of the traditional cond. A cond* expression contains a series of clauses, each of which can use bind* or bind-and* to specify binding variables, use match* or pcase* to specify matching a pattern as a condition, or specify an expression as a condition to evaluate as a test.

Each clause normally has the form (condition body…).

condition can be a Lisp expression, as in cond (see Conditionals). Or it can be (bind* bindings…), (match* pattern datum), (bind-and* bindings…) or (pcase* pattern datum)

(bind* bindings…) means to bind bindings (like the bindings list in let*, see Local Variables) for the body of the clause, and all subsequent clauses. As a condition, it counts as true if the first binding’s value is non-nil.

(bind-and* bindings…) means to bind bindings (like the bindings list in if-let*, see Conditionals) for only the body of the clause. As a condition, it counts as true if none of the bindings evaluate to nil. In addition, if any binding evaluates to nil, the expressions for the values of subsequent bindings are not evaluated.

(match* pattern datum) means to match datum against the specified pattern. The condition counts as true if pattern matches datum. The pattern can specify variables to bind to the parts of datum that they match. (pcase* pattern datum) works in the same way except it uses the Pcase syntax for pattern.

match*, and pcase* normally bind their bindings over the execution of the whole containing clause. However, if the clause is written to specify “non-exit” (see below), the clause’s bindings cover the whole rest of the cond*.

When a clause’s condition is true, and it exits the cond* or is the last clause, the value of the last expression in the clause’s body becomes the return value of the cond* construct.

Non-exit clauses

If the first element of a clause is t or a bind* form, or if it has only one element and that element is a match* or pcase* form, or if it ends with the keyword :non-exit, then this clause never exits the cond* construct. Instead, control falls through to the next clause (if any). Except for a bind-and* clause, the bindings made in condition for the body of the non-exit clause are passed along to the rest of the clauses in this cond* construct.

Note: pcase* does not support :non-exit, and when used in a non-exit clause, it follows the semantics of pcase-let, see Destructuring with pcase Patterns.

Matching clauses

A matching clause looks like (match* pattern datum). It evaluates the expression datum and matches the pattern pattern (which is not evaluated) against it.

pattern allows these kinds of patterns, and those that are lists often include other patterns within them:

_

Matches any value.

keyword

Matches that keyword.

nil

Matches nil.

t

Matches t.

symbol

Matches any value and binds symbol to that value. If symbol has been matched and bound earlier in this pattern, it matches here the same value that it matched before.

regexp

Matches a string if regexp matches it. The match must cover the entire string from its first char to its last.

atom

(Meaning any other kind of non-list not described above.) Matches anything ‘equal’ to it.

(rx regexp)

Uses a regexp specified in s-expression form, as in the function rx (see The rx Structured Regexp Notation, and matches the data that way.

(rx regexp sym0 sym1…)

Uses a regexp specified in s-expression form, and binds the symbols sym0, sym1, and so on to (match-string 0 datum), (match-string 1 datum), and so on. You can use as many syms as regexp matching supports.

`object

Matches any value equal to object.

(cons carpat cdrpat)

Matches a cons cell if carpat matches its car and cdrpat matches its cdr.

(list eltpats…)

Matches a list if the eltpats match its elements. The first eltpat should match the list’s first element. The second eltpat should match the list’s second element. And so on.

(vector eltpats…)

Matches a vector if the eltpats match its elements. The first eltpat should match the vector’s first element. The second eltpat should match the vector’s second element. And so on.

(cdr pattern)

Matches pattern with strict checking of cdrs. That means that list patterns verify that the final cdr is nil. Strict checking is the default.

(cdr-ignore pattern)

Matches pattern with lax checking of cdrs. That means that list patterns do not examine the final cdr.

(and conjuncts…)

Matches each of the conjuncts against the same data. If all of them match, this pattern succeeds. If one conjunct fails, this pattern fails and does not try more conjuncts.

(or disjuncts…)

Matches each of the disjuncts against the same data. If one disjunct succeeds, this pattern succeeds and does not try more disjuncts. If all of them fail, this pattern fails.

(cond*-expander …)

Here the car is a symbol that has a cond*-expander property which defines how to handle it in a pattern. The property value is a function. Trying to match such a pattern calls that function with one argument, the pattern in question (including its car). The function should return an equivalent pattern to be matched instead.

(predicate symbol)

Matches datum if (predicate datum) is true, then binds symbol to datum.

(predicate SYMBOL more-args…)

Matches datum if (predicate datum more-args…) is true, then binds symbol to datum. more-args… can refer to symbols bound earlier in the pattern.

(constrain symbol exp)

Matches datum if the form exp is true. exp can refer to symbols bound earlier in the pattern.