Up: Conditionals
To compare a particular value against various possible cases, the macro
pcase
can come handy. It takes the following form:
(pcase exp branch1 branch2 branch3 ...)
where each branch takes the form (
upattern
body-forms...)
.
It will first evaluate exp and then compare the value against each upattern to see which branch to use, after which it will run the corresponding body-forms. A common use case is to distinguish between a few different constant values:
(pcase (get-return-code x) (`success (message "Done!")) (`would-block (message "Sorry, can't do it now")) (`read-only (message "The shmliblick is read-only")) (`access-denied (message "You do not have the needed rights")) (code (message "Unknown return code %S" code)))
In the last clause, code
is a variable that gets bound to the value that
was returned by (get-return-code x)
.
To give a more complex example, a simple interpreter for a little expression language could look like (note that this example requires lexical binding):
(defun evaluate (exp env) (pcase exp (`(add ,x ,y) (+ (evaluate x env) (evaluate y env))) (`(call ,fun ,arg) (funcall (evaluate fun env) (evaluate arg env))) (`(fn ,arg ,body) (lambda (val) (evaluate body (cons (cons arg val) env)))) ((pred numberp) exp) ((pred symbolp) (cdr (assq exp env))) (_ (error "Unknown expression %S" exp))))
Where `(add ,x ,y)
is a pattern that checks that exp
is a three
element list starting with the symbol add
, then extracts the second and
third elements and binds them to the variables x
and y
.
(pred numberp)
is a pattern that simply checks that exp
is a number, and _
is the catch-all pattern that matches anything.
Here are some sample programs including their evaluation results:
(evaluate '(add 1 2) nil) ;=> 3 (evaluate '(add x y) '((x . 1) (y . 2))) ;=> 3 (evaluate '(call (fn x (add 1 x)) 2) nil) ;=> 3 (evaluate '(sub 1 2) nil) ;=> error
There are two kinds of patterns involved in pcase
, called
U-patterns and Q-patterns. The upattern mentioned above
are U-patterns and can take the following forms:
`
qpatternMore specifically, a Q-pattern can take the following forms:
(
qpattern1 .
qpattern2)
car
matches QPATTERN1 and
whose cdr
matches PATTERN2.
equal
to atom.
,
upattern_
(pred
pred)
nil
when
called with the object being matched.
(or
upattern1 upattern2...)
(and
upattern1 upattern2...)
(guard
exp)
nil
and fails otherwise. It is typically used inside
an and
pattern. For example, (and x (guard (< x 10)))
is a pattern which matches any number smaller than 10 and let-binds it to
the variable x
.