elisp: Pattern matching case statement

 
 10.2.1 Pattern matching case statement
 --------------------------------------
 
 The ‘cond’ form lets you choose between alternatives using predicate
 conditions that compare values of expressions against specific values
 known and written in advance.  However, sometimes it is useful to select
 alternatives based on more general conditions that distinguish between
 broad classes of values.  The ‘pcase’ macro allows you to choose between
 alternatives based on matching the value of an expression against a
 series of patterns.  A pattern can be a literal value (for comparisons
 to literal values you’d use ‘cond’), or it can be a more general
 description of the expected structure of the expression’s value.
 
  -- Macro: pcase expression &rest clauses
      Evaluate EXPRESSION and choose among an arbitrary number of
      alternatives based on the value of EXPRESSION.  The possible
      alternatives are specified by CLAUSES, each of which must be a list
      of the form ‘(PATTERN BODY-FORMS...)’.  ‘pcase’ tries to match the
      value of EXPRESSION to the PATTERN of each clause, in textual
      order.  If the value matches, the clause succeeds; ‘pcase’ then
      evaluates its BODY-FORMS, and returns the value of the last of
      BODY-FORMS.  Any remaining CLAUSES are ignored.
 
      The PATTERN part of a clause can be of one of two types:
      “QPattern”, a pattern quoted with a backquote; or a “UPattern”,
      which is not quoted.  UPatterns are simpler, so we describe them
      first.
 
      Note: In the description of the patterns below, we use “the value
      being matched” to refer to the value of the EXPRESSION that is the
      first argument of ‘pcase’.
 
      A UPattern can have the following forms:
 
      ‘'VAL’
           Matches if the value being matched is ‘equal’ to VAL.
      ‘ATOM’
           Matches any ATOM, which can be a keyword, a number, or a
           string.  (These are self-quoting, so this kind of UPattern is
           actually a shorthand for ‘'ATOM’.)  Note that a string or a
           float matches any string or float with the same
           contents/value.
      ‘_’
           Matches any value.  This is known as “don’t care” or
           “wildcard”.
      ‘SYMBOL’
           Matches any value, and additionally let-binds SYMBOL to the
           value it matched, so that you can later refer to it, either in
           the BODY-FORMS or also later in the pattern.
      ‘(pred PREDFUN)’
           Matches if the predicate function PREDFUN returns non-‘nil’
           when called with the value being matched as its argument.
           PREDFUN can be one of the possible forms described below.
      ‘(guard BOOLEAN-EXPRESSION)’
           Matches if BOOLEAN-EXPRESSION evaluates to non-‘nil’.  This
           allows you to include in a UPattern boolean conditions that
           refer to symbols bound to values (including the value being
           matched) by previous UPatterns.  Typically used inside an
           ‘and’ UPattern, see below.  For example,
           ‘(and x (guard (< x 10)))’ is a pattern which matches any
           number smaller than 10 and let-binds the variable ‘x’ to that
           number.
      ‘(let UPATTERN EXPRESSION)’
           Matches if the specified EXPRESSION matches the specified
           UPATTERN.  This allows matching a pattern against the value of
           an _arbitrary_ expression, not just the expression that is the
           first argument to ‘pcase’.  (It is called ‘let’ because
           UPATTERN can bind symbols to values using the SYMBOL UPattern.
           For example: ‘((or `(key . ,val) (let val 5)) val)’.)
      ‘(app FUNCTION UPATTERN)’
           Matches if FUNCTION applied to the value being matched returns
           a value that matches UPATTERN.  This is like the ‘pred’
           UPattern, except that it tests the result against UPATTERN,
           rather than against a boolean truth value.  The FUNCTION call
           can use one of the forms described below.
      ‘(or UPATTERN1 UPATTERN2...)’
           Matches if one the argument UPatterns matches.  As soon as the
           first matching UPattern is found, the rest are not tested.
           For this reason, if any of the UPatterns let-bind symbols to
           the matched value, they should all bind the same symbols.
      ‘(and UPATTERN1 UPATTERN2...)’
           Matches if all the argument UPatterns match.
 
      The function calls used in the ‘pred’ and ‘app’ UPatterns can have
      one of the following forms:
 
      function symbol, like ‘integerp’
           In this case, the named function is applied to the value being
           matched.
      lambda-function ‘(lambda (ARG) BODY)’
           In this case, the lambda-function is called with one argument,
           the value being matched.
      ‘(FUNC ARGS...)’
           This is a function call with N specified arguments; the
           function is called with these N arguments and an additional
           N+1-th argument that is the value being matched.
 
      Here’s an illustrative example of using UPatterns:
 
           (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 addition, you can use backquoted patterns that are more
      powerful.  They allow matching the value of the EXPRESSION that is
      the first argument of ‘pcase’ against specifications of its
      _structure_.  For example, you can specify that the value must be a
      list of 2 elements whose first element is a specific string and the
      second element is any value with a backquoted pattern like
      ‘`("first" ,second-elem)’.
 
      Backquoted patterns have the form ‘`QPATTERN’ where QPATTERN can
      have the following forms:
 
      ‘(QPATTERN1 . QPATTERN2)’
           Matches if the value being matched is a cons cell whose ‘car’
           matches QPATTERN1 and whose ‘cdr’ matches QPATTERN2.  This
           readily generalizes to backquoted lists as in
           ‘(QPATTERN1 QPATTERN2 ...)’.
      ‘[QPATTERN1 QPATTERN2 ... QPATTERNM]’
           Matches if the value being matched is a vector of length M
           whose ‘0’..‘(M-1)’th elements match QPATTERN1, QPATTERN2 ...
           QPATTERNM, respectively.
      ‘ATOM’
           Matches if corresponding element of the value being matched is
           ‘equal’ to the specified ATOM.
      ‘,UPATTERN’
           Matches if the corresponding element of the value being
           matched matches the specified UPATTERN.
 
      Note that uses of QPatterns can be expressed using only UPatterns,
      as QPatterns are implemented on top of UPatterns using
      ‘pcase-defmacro’, described below.  However, using QPatterns will
      in many cases lead to a more readable code.
 
    Here is an example of using ‘pcase’ to implement a simple interpreter
 for a little expression language (note that this example requires
 lexical binding, SeeLexical 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))))
 
    Here ‘`(add ,x ,y)’ is a pattern that checks that ‘exp’ is a
 three-element list starting with the literal symbol ‘add’, then extracts
 the second and third elements and binds them to the variables ‘x’ and
 ‘y’.  Then it evaluates ‘x’ and ‘y’ and adds the results.  The ‘call’
 and ‘fn’ patterns similarly implement two flavors of function calls.
 ‘(pred numberp)’ is a pattern that simply checks that ‘exp’ is a number
 and if so, evaluates it.  ‘(pred symbolp)’ matches symbols, and returns
 their association.  Finally, ‘_’ is the catch-all pattern that matches
 anything, so it’s suitable for reporting syntax errors.
 
    Here are some sample programs in this small language, 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
 
    Additional UPatterns can be defined using the ‘pcase-defmacro’ macro.
 
  -- Macro: pcase-defmacro name args &rest body
      Define a new kind of UPattern for ‘pcase’.  The new UPattern will
      be invoked as ‘(NAME ACTUAL-ARGS)’.  The BODY should describe how
      to rewrite the UPattern NAME into some other UPattern.  The
      rewriting will be the result of evaluating BODY in an environment
      where ARGS are bound to ACTUAL-ARGS.