unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* pcase bindings in patterns with complicated logic
@ 2024-01-13  3:54 Richard Stallman
  2024-01-13 19:58 ` Ihor Radchenko
  2024-01-14  7:03 ` Thierry Volpiatto
  0 siblings, 2 replies; 21+ messages in thread
From: Richard Stallman @ 2024-01-13  3:54 UTC (permalink / raw)
  To: emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

I'm trying to figure out how pcase behaves in terms of which pattern
variables are actually bound, depending on which parts of a case's
pattern succeeds in matching.  That wasn't clear to me from the docs I
read.

I tried this example:

(setq x1 nil x2 nil y1 nil y2 nil)

(pcase '(foo 5)
  ((or `(,(and (pred symbolp) x1) ,(and (pred symbolp) y1))
       `(,(and (pred symbolp) x2) ,(and (pred numberp) y2)))
   `(,x1 ,y1 ,x2 ,y2)))

=> (nil nil foo 5)

So it seems that unless a match for a variable is included in the
branch of the matching tree that actually completes, its variable is
not set.

But then I tried

(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?

If so, do people like that behavior?  Is it easy to use?  Would anyone
prefer a different behavior for cases like this?

The question is, how should cond* handle this?  Just like pcase, or
something different?


-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-13  3:54 pcase bindings in patterns with complicated logic Richard Stallman
@ 2024-01-13 19:58 ` Ihor Radchenko
  2024-01-14  6:58   ` Thierry Volpiatto
  2024-01-15  3:13   ` Richard Stallman
  2024-01-14  7:03 ` Thierry Volpiatto
  1 sibling, 2 replies; 21+ messages in thread
From: Ihor Radchenko @ 2024-01-13 19:58 UTC (permalink / raw)
  To: rms; +Cc: emacs-devel

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.
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



-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-13 19:58 ` Ihor Radchenko
@ 2024-01-14  6:58   ` Thierry Volpiatto
  2024-01-14  7:27     ` Thierry Volpiatto
  2024-01-14 15:42     ` Ihor Radchenko
  2024-01-15  3:13   ` Richard Stallman
  1 sibling, 2 replies; 21+ messages in thread
From: Thierry Volpiatto @ 2024-01-14  6:58 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: rms, emacs-devel

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



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-13  3:54 pcase bindings in patterns with complicated logic Richard Stallman
  2024-01-13 19:58 ` Ihor Radchenko
@ 2024-01-14  7:03 ` Thierry Volpiatto
  1 sibling, 0 replies; 21+ messages in thread
From: Thierry Volpiatto @ 2024-01-14  7:03 UTC (permalink / raw)
  To: Richard Stallman; +Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

> I'm trying to figure out how pcase behaves in terms of which pattern
> variables are actually bound, depending on which parts of a case's
> pattern succeeds in matching.  That wasn't clear to me from the docs I
> read.
>
> I tried this example:
>
> (setq x1 nil x2 nil y1 nil y2 nil)
>
> (pcase '(foo 5)
>   ((or `(,(and (pred symbolp) x1) ,(and (pred symbolp) y1))
>        `(,(and (pred symbolp) x2) ,(and (pred numberp) y2)))
>    `(,x1 ,y1 ,x2 ,y2)))
>
> => (nil nil foo 5)
>
> So it seems that unless a match for a variable is included in the
> branch of the matching tree that actually completes, its variable is
> not set.
>
> But then I tried
>
> (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.

To avoid this you could write instead:

    (pcase '(foo 5)
      (`(,(and (pred symbolp) a1)
          ,(and (or (pred symbolp) (pred numberp)) b1))
       `(,a1 ,b1)))

-- 
Thierry



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-14  6:58   ` Thierry Volpiatto
@ 2024-01-14  7:27     ` Thierry Volpiatto
  2024-01-14 15:42     ` Ihor Radchenko
  1 sibling, 0 replies; 21+ messages in thread
From: Thierry Volpiatto @ 2024-01-14  7:27 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: rms, emacs-devel

Thierry Volpiatto <thievol@posteo.net> writes:

> 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).

For this example, sorry I confuse `add` and `app` (proof it is confusing
:-)).

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

Here read `app` instead of `add`.

-- 
Thierry



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-14  6:58   ` Thierry Volpiatto
  2024-01-14  7:27     ` Thierry Volpiatto
@ 2024-01-14 15:42     ` Ihor Radchenko
  2024-01-14 15:58       ` Thierry Volpiatto
  1 sibling, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-01-14 15:42 UTC (permalink / raw)
  To: Thierry Volpiatto; +Cc: rms, emacs-devel

Thierry Volpiatto <thievol@posteo.net> writes:

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

Isn't it explained right in the manual?

‘(app FUNCTION PATTERN)’
     Matches if FUNCTION called on EXPVAL returns a value that matches
     PATTERN.  FUNCTION can take one of the forms described for ‘pred’,
     above.  Unlike ‘pred’, however, ‘app’ tests the result against
     PATTERN, rather than against a boolean truth value.

> 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.

Compiler takes care about this warnings. For example,
(pcase '(1)
  ((pred (not cdr)) "true"))

in Emacs 26 will indicate problems

Compiling file /tmp/test.el at Sun Jan 14 16:41:32 2024
test.el:2:15:Warning: reference to free variable ‘cdr’

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-14 15:42     ` Ihor Radchenko
@ 2024-01-14 15:58       ` Thierry Volpiatto
  2024-01-14 16:21         ` Ihor Radchenko
  0 siblings, 1 reply; 21+ messages in thread
From: Thierry Volpiatto @ 2024-01-14 15:58 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: rms, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1480 bytes --]

Ihor Radchenko <yantar92@posteo.net> writes:

> Thierry Volpiatto <thievol@posteo.net> writes:
>
>> [ BTW I don't understand why `app` pattern exists as long as now `pred` is
>> supporting an extra arg ]
>
> Isn't it explained right in the manual?
>
> ‘(app FUNCTION PATTERN)’
>      Matches if FUNCTION called on EXPVAL returns a value that matches
>      PATTERN.  FUNCTION can take one of the forms described for ‘pred’,
>      above.  Unlike ‘pred’, however, ‘app’ tests the result against
>      PATTERN, rather than against a boolean truth value.

Perhaps it is right but I don't understand it, an example in the manual
would be welcome (if there is one I missed it).

>> 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.
>
> Compiler takes care about this warnings. For example,
> (pcase '(1)
>   ((pred (not cdr)) "true"))
>
> in Emacs 26 will indicate problems
>
> Compiling file /tmp/test.el at Sun Jan 14 16:41:32 2024
> test.el:2:15:Warning: reference to free variable ‘cdr’

I already hit this warning and had hard time figuring what was wrong, in
test.el it is easy to find but in a large file the compiler doesn't
bring you always to the right place.

-- 
Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 686 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-14 15:58       ` Thierry Volpiatto
@ 2024-01-14 16:21         ` Ihor Radchenko
  2024-01-14 17:54           ` Thierry Volpiatto
  0 siblings, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-01-14 16:21 UTC (permalink / raw)
  To: Thierry Volpiatto; +Cc: rms, emacs-devel

Thierry Volpiatto <thievol@posteo.net> writes:

>>> [ BTW I don't understand why `app` pattern exists as long as now `pred` is
>>> supporting an extra arg ]
>>
>> Isn't it explained right in the manual?
>>
>> ‘(app FUNCTION PATTERN)’
>>      Matches if FUNCTION called on EXPVAL returns a value that matches
>>      PATTERN.  FUNCTION can take one of the forms described for ‘pred’,
>>      above.  Unlike ‘pred’, however, ‘app’ tests the result against
>>      PATTERN, rather than against a boolean truth value.
>
> Perhaps it is right but I don't understand it, an example in the manual
> would be welcome (if there is one I missed it).

Does this example help?

(pcase '(1 2 3)
  ((app cdr `(2 ,c)) (format "Match: %S" c)))

You cannot easily do the same with pred.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-14 16:21         ` Ihor Radchenko
@ 2024-01-14 17:54           ` Thierry Volpiatto
  2024-01-16  3:32             ` Richard Stallman
  0 siblings, 1 reply; 21+ messages in thread
From: Thierry Volpiatto @ 2024-01-14 17:54 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: rms, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 915 bytes --]

Ihor Radchenko <yantar92@posteo.net> writes:

> Thierry Volpiatto <thievol@posteo.net> writes:
>
>>>> [ BTW I don't understand why `app` pattern exists as long as now `pred` is
>>>> supporting an extra arg ]
>>>
>>> Isn't it explained right in the manual?
>>>
>>> ‘(app FUNCTION PATTERN)’
>>>      Matches if FUNCTION called on EXPVAL returns a value that matches
>>>      PATTERN.  FUNCTION can take one of the forms described for ‘pred’,
>>>      above.  Unlike ‘pred’, however, ‘app’ tests the result against
>>>      PATTERN, rather than against a boolean truth value.
>>
>> Perhaps it is right but I don't understand it, an example in the manual
>> would be welcome (if there is one I missed it).
>
> Does this example help?
>
> (pcase '(1 2 3)
>   ((app cdr `(2 ,c)) (format "Match: %S" c)))
>
> You cannot easily do the same with pred.

Yes, thanks.

-- 
Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 686 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-13 19:58 ` Ihor Radchenko
  2024-01-14  6:58   ` Thierry Volpiatto
@ 2024-01-15  3:13   ` Richard Stallman
  1 sibling, 0 replies; 21+ messages in thread
From: Richard Stallman @ 2024-01-15  3:13 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > 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.

It looks like you've observed the same behavior that I observed.  It
seems reasonable to me -- I can't think of a different behavior that
would be better -- so I've impleented that same behavior in cond*.

Thanks.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-14 17:54           ` Thierry Volpiatto
@ 2024-01-16  3:32             ` Richard Stallman
  2024-01-16 13:18               ` Ihor Radchenko
  0 siblings, 1 reply; 21+ messages in thread
From: Richard Stallman @ 2024-01-16  3:32 UTC (permalink / raw)
  To: Thierry Volpiatto; +Cc: emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > (pcase '(1 2 3)
  > >   ((app cdr `(2 ,c)) (format "Match: %S" c)))

cond* can do this without introducing a special feature for it:

  (cond* ((match* `(2 ,c) (cdr '(1 2 3)))
          (format "Match: %S" c)))

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-16  3:32             ` Richard Stallman
@ 2024-01-16 13:18               ` Ihor Radchenko
  2024-01-18  3:37                 ` Richard Stallman
  0 siblings, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-01-16 13:18 UTC (permalink / raw)
  To: rms; +Cc: Thierry Volpiatto, emacs-devel

Richard Stallman <rms@gnu.org> writes:

>   > > (pcase '(1 2 3)
>   > >   ((app cdr `(2 ,c)) (format "Match: %S" c)))
>
> cond* can do this without introducing a special feature for it:
>
>   (cond* ((match* `(2 ,c) (cdr '(1 2 3)))
>           (format "Match: %S" c)))

What about

(pcase '(1 2 3)
  ((and `(1 . ,_)
   (app cdr `(2 ,c)))
     (format "Match: %S" c)))

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-16 13:18               ` Ihor Radchenko
@ 2024-01-18  3:37                 ` Richard Stallman
  2024-01-18 13:13                   ` Ihor Radchenko
  0 siblings, 1 reply; 21+ messages in thread
From: Richard Stallman @ 2024-01-18  3:37 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: thievol, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > cond* can do this without introducing a special feature for it:
  > >
  > >   (cond* ((match* `(2 ,c) (cdr '(1 2 3)))
  > >           (format "Match: %S" c)))

  > What about

  > (pcase '(1 2 3)
  >   ((and `(1 . ,_)
  >    (app cdr `(2 ,c)))
  >      (format "Match: %S" c)))

That uss, once again, the construct `app'.  pcse can do this
but needs a special feature to do it.

The point is that cond* can do this without the need of a special
extra feature.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-18  3:37                 ` Richard Stallman
@ 2024-01-18 13:13                   ` Ihor Radchenko
  2024-01-20  3:39                     ` Richard Stallman
  0 siblings, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-01-18 13:13 UTC (permalink / raw)
  To: rms; +Cc: thievol, emacs-devel

Richard Stallman <rms@gnu.org> writes:

>   > (pcase '(1 2 3)
>   >   ((and `(1 . ,_)
>   >    (app cdr `(2 ,c)))
>   >      (format "Match: %S" c)))
>
> That uss, once again, the construct `app'.  pcse can do this
> but needs a special feature to do it.
>
> The point is that cond* can do this without the need of a special
> extra feature.

My question was whether cond* can be used to implement an equivalent
match as in my example above. AFAIU, cond* cannot match against multiple
values at once.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-18 13:13                   ` Ihor Radchenko
@ 2024-01-20  3:39                     ` Richard Stallman
  2024-01-20 12:48                       ` Ihor Radchenko
  0 siblings, 1 reply; 21+ messages in thread
From: Richard Stallman @ 2024-01-20  3:39 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: thievol, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > My question was whether cond* can be used to implement an equivalent
  > match as in my example above.

The `or' pattern should do that job.
In what way is it not sufficient?

                                  AFAIU, cond* cannot match against multiple
  > values at once.

With the natural meaning, yes it can.  Perhaps we are miscommunicating.
Could you explain what "match against multiple values at once" means to you?

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-20  3:39                     ` Richard Stallman
@ 2024-01-20 12:48                       ` Ihor Radchenko
  2024-01-21  3:06                         ` Richard Stallman
  0 siblings, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-01-20 12:48 UTC (permalink / raw)
  To: rms; +Cc: thievol, emacs-devel

Richard Stallman <rms@gnu.org> writes:

>   > My question was whether cond* can be used to implement an equivalent
>   > match as in my example above.
>
> The `or' pattern should do that job.
> In what way is it not sufficient?
>
>                                   AFAIU, cond* cannot match against multiple
>   > values at once.
>
> With the natural meaning, yes it can.  Perhaps we are miscommunicating.
> Could you explain what "match against multiple values at once" means to you?

I think we are indeed miscommunicating.
Let me provide another, more clear, example.

(pcase '((foo . 1) (bar . 2) (baz . 3))
  ((and `((foo . 1) . ,_)
	(app (mapcar #'cdr) `(,_ ,_ ,c)))
   (format "Match: %S" c)))

The above matches `((foo . 1) . ,_) against '((foo . 1) (bar . 2) (baz . 3))
and then matches `(,_ ,_ ,c) against a different value - '(1 2 3)

AFAIU, this is not possible with cond*.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-20 12:48                       ` Ihor Radchenko
@ 2024-01-21  3:06                         ` Richard Stallman
  2024-01-21 14:06                           ` Ihor Radchenko
  0 siblings, 1 reply; 21+ messages in thread
From: Richard Stallman @ 2024-01-21  3:06 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: thievol, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > (pcase '((foo . 1) (bar . 2) (baz . 3))
  >   ((and `((foo . 1) . ,_)
  > 	(app (mapcar #'cdr) `(,_ ,_ ,c)))
  >    (format "Match: %S" c)))

  > The above matches `((foo . 1) . ,_) against '((foo . 1) (bar . 2) (baz . 3))
  > and then matches `(,_ ,_ ,c) against a different value - '(1 2 3)

One of the basic benefits of cond* is that you're not compelled to match
all the patterns against the same data object.

I am not confident I understand app pattern, but if it does what I now
think, the equivalent of (app (mapcar #'cdr) `(,_ ,_ ,c))) would be
this:

  (match* `(,_ ,_ ,c) (mapcar 'car  '((foo . 1) (bar . 2) (baz . 3))))

What cond* cannot do is apply `and' to two different match* clauses
which test different objects.  I could add that capability.  I could
also add `app', if that is worth adding.  Its absence is not a fundamental
design issue, just that it dud not seem necessary.

That example wan't a solution to a real problem, so I am not convinced
this is a real gap in cond*.  If I see this sort of situation in a
real problem, that will convince me I should do something about this.

Thanks for helping me understand this issue.

  
-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-21  3:06                         ` Richard Stallman
@ 2024-01-21 14:06                           ` Ihor Radchenko
  2024-01-23 13:40                             ` Richard Stallman
  2024-01-23 15:08                             ` Stefan Monnier via Emacs development discussions.
  0 siblings, 2 replies; 21+ messages in thread
From: Ihor Radchenko @ 2024-01-21 14:06 UTC (permalink / raw)
  To: rms; +Cc: thievol, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> I am not confident I understand app pattern, but if it does what I now
> think, the equivalent of (app (mapcar #'cdr) `(,_ ,_ ,c))) would be
> this:
>
>   (match* `(,_ ,_ ,c) (mapcar 'car  '((foo . 1) (bar . 2) (baz . 3))))

Yes.

> What cond* cannot do is apply `and' to two different match* clauses
> which test different objects.  I could add that capability.

You understand correctly - `and' for different match* clauses is what I
pointed to.

> ... I could also add `app', if that is worth adding. Its absence is
> not a fundamental design issue, just that it dud not seem necessary.

`app' is actually a more limited version of what you can do when
combining multiple match* clauses - match* clauses can test completely
unrelated objects, while pcase's `app' can only test a transformed first
pcase argument.

So, I do not think that `app' is required if combining match* clauses is
allowed.

> That example wan't a solution to a real problem, so I am not convinced
> this is a real gap in cond*.  If I see this sort of situation in a
> real problem, that will convince me I should do something about this.

I looked up the use of pcase's `app' pattern across the packages I use
and inside Emacs source code. There are only several trivial uses,
actually:

(defun engrave-faces-preset-style (faces)
  "Return the preset style for FACES, should it exist.
Unconditionally returns nil when FACES is default."
  (pcase faces
    ('default nil)
    ((pred symbolp)
     (assoc faces engrave-faces-preset-styles))
    ((and (pred listp) (app length 1)) ; <--- here
     (assoc (car faces) engrave-faces-preset-styles))))

(defun octave--indent-new-comment-line (orig &rest args)
  (pcase (syntax-ppss)
    ((app ppss-string-terminator ?\')
     (user-error "Cannot split a single-quoted string"))
    ((app ppss-string-terminator ?\")
     (insert octave-string-continuation-marker))
    ((pred (not ppss-comment-depth))
     (delete-horizontal-space)
     (unless (octave-smie--in-parens-p)
       (insert " " octave-continuation-string))))
  (apply orig args)
  (indent-according-to-mode))

and a couple of internal pcase uses that are there to extend pcase -
`rx--pcase-expand', `seq--make-pcase-bindings',
`map--make-pcase-bindings', and (pcase-defmacro eieio...)

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-21 14:06                           ` Ihor Radchenko
@ 2024-01-23 13:40                             ` Richard Stallman
  2024-01-23 15:08                             ` Stefan Monnier via Emacs development discussions.
  1 sibling, 0 replies; 21+ messages in thread
From: Richard Stallman @ 2024-01-23 13:40 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: thievol, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > So, I do not think that `app' is required if combining match* clauses is
  > allowed.

I will think about implementing conjunctions of match* clauses
after I have the existing functionality working and installed.

Thanks for suggesting this.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-21 14:06                           ` Ihor Radchenko
  2024-01-23 13:40                             ` Richard Stallman
@ 2024-01-23 15:08                             ` Stefan Monnier via Emacs development discussions.
  2024-01-23 19:59                               ` Stefan Monnier via Emacs development discussions.
  1 sibling, 1 reply; 21+ messages in thread
From: Stefan Monnier via Emacs development discussions. @ 2024-01-23 15:08 UTC (permalink / raw)
  To: emacs-devel

> I looked up the use of pcase's `app' pattern across the packages I use
> and inside Emacs source code. There are only several trivial uses,
> actually:

The `app` pattern is mostly for internal use when defining other
patterns.  It's key to the implementation of patterns like backquote so
it's very important, but you'll rarely see it "out and about" in
a `pcase` or `pcase-let` statement.


        Stefan




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: pcase bindings in patterns with complicated logic
  2024-01-23 15:08                             ` Stefan Monnier via Emacs development discussions.
@ 2024-01-23 19:59                               ` Stefan Monnier via Emacs development discussions.
  0 siblings, 0 replies; 21+ messages in thread
From: Stefan Monnier via Emacs development discussions. @ 2024-01-23 19:59 UTC (permalink / raw)
  To: emacs-devel; +Cc: Stefan Monnier

> The `app` pattern is mostly for internal use when defining other
> patterns.  It's key to the implementation of patterns like backquote so
> it's very important, but you'll rarely see it "out and about" in
> a `pcase` or `pcase-let` statement.

BTW, if you want help to understand the general design of Pcase, a good
read is that of the design of `match` for Racket:

    Extensible Pattern Matching in an Extensible Language
    Sam Tobin-Hochstadt, 2010
    https://arxiv.org/abs/1106.2578

I didn't know about that `match` construct when I started Pcase (and now
that I actually pay attention to the publication date I realize that
maybe it's not because I missed it in my searches but because it came
out around the same time), but when I found it, I "realigned" Pcase to
be more like Racket's `match`.  The implementation is not quite the same
because sadly our ELisp implementation doesn't handle (tail) calls quite
as efficiently as Racket, but there's a large overlap when it comes to
the exposed functionality.


        Stefan




^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2024-01-23 19:59 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-13  3:54 pcase bindings in patterns with complicated logic Richard Stallman
2024-01-13 19:58 ` Ihor Radchenko
2024-01-14  6:58   ` Thierry Volpiatto
2024-01-14  7:27     ` Thierry Volpiatto
2024-01-14 15:42     ` Ihor Radchenko
2024-01-14 15:58       ` Thierry Volpiatto
2024-01-14 16:21         ` Ihor Radchenko
2024-01-14 17:54           ` Thierry Volpiatto
2024-01-16  3:32             ` Richard Stallman
2024-01-16 13:18               ` Ihor Radchenko
2024-01-18  3:37                 ` Richard Stallman
2024-01-18 13:13                   ` Ihor Radchenko
2024-01-20  3:39                     ` Richard Stallman
2024-01-20 12:48                       ` Ihor Radchenko
2024-01-21  3:06                         ` Richard Stallman
2024-01-21 14:06                           ` Ihor Radchenko
2024-01-23 13:40                             ` Richard Stallman
2024-01-23 15:08                             ` Stefan Monnier via Emacs development discussions.
2024-01-23 19:59                               ` Stefan Monnier via Emacs development discussions.
2024-01-15  3:13   ` Richard Stallman
2024-01-14  7:03 ` Thierry Volpiatto

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).