cl-match compares the structure of a value with a pattern and binds variables to parts of the structure. This can be done with either of two macros: MATCH and IFMATCH. IFMATCH takes three arguments and a body of code. The arguments are a pattern, an expression whose value will be compared with the pattern, and a form to be evaluated on a match. The body is evaluated if the pattern doesn't match.
A value can be tested against multiple patterns with MATCH, which is related to IFMATCH in the same way that COND is related to IF. New patterns can be defined by the user with DEFPATTERN.
All patterns are written as s-expressions. A pattern can be either an atom or a list. A literal atom generates an EQL test. A symbol generates a variable binding on its first occurance in the pattern, and an EQL test on each subsequent occurance. The wildcard symbol _ matches anything.
Lists are used to represent compound patterns, which usually take one or more arguments. Most arguments either are or contain patterns to be matched by subsections of the value being matched by the overall pattern. These patterns are currently implemented: ACSRS, AND, ARRAY, AS, CONS, LIST, LIST*, OR, QUOTE, SLOTS, STRUCT, TYPE, VALS, and VEC. Each OR pattern creates branches for alternative patterns, and a VALS pattern at the top level of the overall pattern will bind multiple values.
Guards are written as WHEN forms, where the first argument is the guard test, and the second argument is the pattern. The second argument is optional, and defaults to _. If one or more OR patterns are present, branch-specific guards can be included immediately inside the corresponding ORs. Otherwise, only the outermost form can be a guard.
New patterns can be defined with the DEFPATTERN macro. Built-in patterns can be overridden, and overridden built-in patterns can be accessed by specifying their names as strings instead of symbols.
Defines a new pattern. The pattern will be a list whose first element is the symbol name and whose remainder is specified by args. The macro is expected to return a valid pattern.
Evaluates expr, and compares it to pattern, binding names in pattern as they're encountered. Evaluates onmatch if the pattern matches, otherwise evaluates on-mismatch.
Same as ifmatch, except there are no on-mismatch forms, the onmatch forms are inlined, and an error is signaled on mismatch.
Evaluates expr, then compares the resulting value to each pattern in succession until a pattern matches, then evaluates the body immediately following the successful pattern.
acsrs &rest forms
and &rest patterns
as name pattern
cons p-car p-cdr
list &rest patterns
list* &rest patterns
or &rest patterns
slots &rest slot-forms
struct prefix &rest field-forms
type type &optional pattern
vals &rest patterns
vec patrn-list &optional elt-type
when test &optional pattern
Here's a function that flattens a list by recursively looking at the structure of its parts. Empty sublists (NILs) are retained in the result.
(defun flatten (x) (match x ((type atom) (list x)) ((list car) (flatten car)) ;only one element ((cons car cdr) (append (flatten car) (flatten cdr)))))
NOT patterns would be nice if they didn't mess with OR patterns and variable bindings. But they have some tricky interactions, so they're not implemented yet.
Custom structure predicates aren't supported yet.