emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: pcase bindings in patterns with complicated logic


From: Thierry Volpiatto
Subject: Re: pcase bindings in patterns with complicated logic
Date: Sun, 14 Jan 2024 06:58:13 +0000

Ihor Radchenko <yantar92@posteo.net> writes:

> Richard Stallman <rms@gnu.org> writes:
>
>> (pcase '(foo 5)
>>   ((or `(,(and (pred symbolp) a1) ,(and (pred symbolp) b1))
>>        `(,(and (pred symbolp) a2) ,(and (pred numberp) b2)))
>>    `(,a1 ,b1 ,a2 ,b2)))
>>
>> => (nil nil foo 5)
>>
>> That surrised me, since outside the pcase, all four variables
>> are unbound and referring to them gets errors.
>>
>> So it seems that all the pattern variables in the curren clause are
>> bound somehow if that clause succeeds, but only some of them get
>> significant values.
>>
>> Is that an accurate general statement of how pcase handles binding
>> pattern variables?
>
> This looks like a bug.

This is not a bug, this is documented earlier in documentation:

‘(or PATTERN1 PATTERN2...)’
     Attempts to match PATTERN1, PATTERN2, ..., in order, until one of
     them succeeds.  In that case, ‘or’ likewise matches, and the rest
     of the sub-patterns are not tested.

     To present a consistent environment (*note Intro Eval::) to
     BODY-FORMS (thus avoiding an evaluation error on match), the set of
     variables bound by the pattern is the union of the variables bound
     by each sub-pattern.  If a variable is not bound by the sub-pattern
     that matched, then it is bound to ‘nil’.

But I guess the rest of the documentation has not been updated.
 
> The manual has a dedicated paragraph explaining the above scenario.
> However, on the latest Emacs master, "void variable" errors are not
> thrown, in contradiction with what the manual states.
>
>   3. On match, the clause's body forms can reference the set of symbols
>      the pattern let-binds.  When SEQPAT is ‘and’, this set is the union
>      of all the symbols each of its sub-patterns let-binds.  This makes
>      sense because, for ‘and’ to match, all the sub-patterns must match.
>
>      When SEQPAT is ‘or’, things are different: ‘or’ matches at the
>      first sub-pattern that matches; the rest of the sub-patterns are
>      ignored.  It makes no sense for each sub-pattern to let-bind a
>      different set of symbols because the body forms have no way to
>      distinguish which sub-pattern matched and choose among the
>      different sets.  For example, the following is invalid:
>
>           (require 'cl-lib)
>           (pcase (read-number "Enter an integer: ")
>             ((or (and (pred cl-evenp)
>                       e-num)      ; bind ‘e-num’ to EXPVAL
>                  o-num)           ; bind ‘o-num’ to EXPVAL
>              (list e-num o-num)))
>
>           Enter an integer: 42
>           error→ Symbol’s value as variable is void: o-num
>           Enter an integer: 149
>           error→ Symbol’s value as variable is void: e-num

This should be updated to fit with the (or PATTERN1 PATTERN2...)
documentation.

I guess there is other examples in documentation that are mismatching
with the actual behavior of pcase or are just confusing like this one in
"11.4.4 Destructuring with ‘pcase’ Patterns":

       (pcase my-list
         (`(add ,x ,y)  (message "Contains %S and %S" x y)))

I guess this example has been added before the pattern `add` exists.
Here `add` is a symbol like any other symbol and has no particular
meaning but it is confusing for reader that has not completely
integrated previous sections (I would use `foo` instead).

[ BTW I don't understand why `add` pattern exists as long as now `pred` is
supporting an extra arg ]

Also I would give a warning to extensions developers that want
compatibility with older emacs:

pcase has evolved and doesn't behave as in older emacs, so try you pcase
statements on each emacs you want to support, for example (pred (not
...)) is not supported in older Emacs.

-- 
Thierry



reply via email to

[Prev in Thread] Current Thread [Next in Thread]