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.