But why doesn't pred
work?
Because pred
passes the value being matched as the last argument to its predicate.
Could you explain a bit more, maybe contrasting examples?
Let me start by quoting the current docstring of pcase
in Emacs 27:
pcase is a Lisp macro in `pcase.el'.
(pcase EXP &rest CASES)
Probably introduced at or before Emacs version 24.1.
Evaluate EXP to get EXPVAL; try passing control to one of CASES.
CASES is a list of elements of the form (PATTERN CODE...).
For the first CASE whose PATTERN "matches" EXPVAL,
evaluate its CODE..., and return the value of the last form.
If no CASE has a PATTERN that matches, return nil.
Each PATTERN expands, in essence, to a predicate to call
on EXPVAL. When the return value of that call is non-nil,
PATTERN matches. PATTERN can take one of the forms:
_ matches anything.
'VAL matches if EXPVAL is `equal' to VAL.
KEYWORD shorthand for 'KEYWORD
INTEGER shorthand for 'INTEGER
STRING shorthand for 'STRING
SYMBOL matches anything and binds it to SYMBOL.
If a SYMBOL is used twice in the same pattern
the second occurrence becomes an `eq'uality test.
(pred FUN) matches if FUN called on EXPVAL returns non-nil.
(app FUN PAT) matches if FUN called on EXPVAL matches PAT.
(guard BOOLEXP) matches if BOOLEXP evaluates to non-nil.
(let PAT EXPR) matches if EXPR matches PAT.
(and PAT...) matches if all the patterns match.
(or PAT...) matches if any of the patterns matches.
FUN in `pred' and `app' can take one of the forms:
SYMBOL or (lambda ARGS BODY)
call it with one argument
(F ARG1 .. ARGn)
call F with ARG1..ARGn and EXPVAL as n+1'th argument
FUN, BOOLEXP, EXPR, and subsequent PAT can refer to variables
bound earlier in the pattern by a SYMBOL pattern.
Additional patterns can be defined using `pcase-defmacro'.
See Info node `(elisp) Pattern-Matching Conditional' in the
Emacs Lisp manual for more information and examples.
The Elisp manual section (elisp) pcase Macro
expounds a bit on this:
‘(pred FUNCTION)’
Matches if the predicate FUNCTION returns non-‘nil’ when called on
EXPVAL. the predicate FUNCTION can have one of the following
forms:
function name (a symbol)
Call the named function with one argument, EXPVAL.
Example: ‘integerp’
lambda expression
Call the anonymous function with one argument, EXPVAL (see
Lambda Expressions).
Example: ‘(lambda (n) (= 42 n))’
function call with N args
Call the function (the first element of the function call)
with N arguments (the other elements) and an additional N+1-th
argument that is EXPVAL.
Example: ‘(= 42)’
In this example, the function is ‘=’, N is one, and the actual
function call becomes: ‘(= 42 EXPVAL)’.
‘(guard BOOLEAN-EXPRESSION)’
Matches if BOOLEAN-EXPRESSION evaluates to non-‘nil’.
and gives a few examples:
Example: Using ‘and’
--------------------
A common idiom is to write a pattern starting with ‘and’, with one or
more SYMBOL sub-patterns providing bindings to the sub-patterns that
follow (as well as to the body forms). For example, the following
pattern matches single-digit integers.
(and
(pred integerp)
n ; bind ‘n’ to EXPVAL
(guard (<= -9 n 9)))
First, ‘pred’ matches if ‘(integerp EXPVAL)’ evaluates to non-‘nil’.
Next, ‘n’ is a SYMBOL pattern that matches anything and binds ‘n’ to
EXPVAL. Lastly, ‘guard’ matches if the boolean expression ‘(<= -9 n 9)’
(note the reference to ‘n’) evaluates to non-‘nil’. If all these
sub-patterns match, ‘and’ matches.
In other words, the following:
(pcase x
((pred (< y 1)) z))
expands to something like:
(and (< y 1 x) z)
Whereas this:
(pcase x
((guard (< y 1)) z))
expands to something like:
(and (< y 1) z)