[Top][All Lists]

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

pcase pattern syntax (was: Replace trivial pcase occurrences in the Emac

From: Stefan Monnier
Subject: pcase pattern syntax (was: Replace trivial pcase occurrences in the Emacs sources)
Date: Wed, 24 Oct 2018 09:03:51 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux)

> (pcase value
>   (`(,_ 1 2)
>    (message "Matched a list of anything followed by (1 2)")))
> It is not clear to me why I couldn't simply write:
> (pcase value
>   ((_ 1 2)
>    (message "Matched a list of anything followed by (1 2)")))

The reason is simple: because pcase uses a more verbose pattern syntax.
There are many different choices for pattern syntax, with various
tradeoffs between conciseness, regularity, and extensibility.

pcase's syntax leans in favor of regularity and extensibility to the
detriment of conciseness.

In your above example, if you allow (_ 1 2) to mean the same as pcase's
`(,_ 1 2), then you need some special syntax for the case where you
meant to match the same as pcase's '(_ 1 2).

> would then match lists of the form (1 2 3 3), not (1 2 3 4). If you
> need to bind multiple values, I could imagine using something like:
> (pcase value
>   ((1 2 %1 %2)
>    (message "Matched 1, 2, something now bound to %1, and something (else) 
> bound to %2")))

that's getting pretty close to (1 2 ,x ,y): the only differences being
the use of % instead of comma and the absence of a surrounding backquote.

> why not write:
> ```
> (pcase value
>   ((1 2 (or 3 4)
>     (and (stringp %)
>          (string> "aaa" %)
>          (> (length %) 10)))
>    (message "Matched 1, 2, 3 or 4, and a long string "
>             "that is lexically greater than 'aaa'")))

Why wouldn't that be matching the same as pcase's

    (pcase value
      (`(1 2 (or 3 4)
        (and (stringp ,x)
             (string> "aaa" ,y)
             (> (length ,z) 10)))
       (message "Matched 1, 2, 3 or 4, and a long string "
                "that is lexically greater than 'aaa'")))

or alternatively, what special syntax would you introduce in order to
say "this (or 3 4) shouldn't match "either 3 or 4" but should match
a the 3-element list (or 3 4)"?

> uses `(and foo (guard ...))' to bind a value to `foo' and apply
> a predicate to it. That's a coding pattern that you need to be
> familiar with in order to understand what it does. (John explains it
> in his tutorial, but if I had met this in the wild, I'd probably be
> puzzled by it at first). The % syntax would seem to make this simpler
> as well:

Yes, the and+guard thingy sucks.  I've been thinking of changing `guard`
so it automatically does an `and`, i.e. make it so that

    (guard foo EXP)

is the same as

    (and foo (guard EXP))

but I don't find this terribly good either.  Note that you can also
write it as

    (pred (lambda (foo) EXP))

which is clearly not more friendly but I just mention it in case it
might help someone come up with yet another solution.

Many pattern matching systems don't have guards as part of the patterns
and instead have them "on the side", in which case you'd write

    ... ,foo ...

in the pattern and

    (guard EXP)

elsewhere.  I find this to be a nice way to solve the problem, but:
- I don't know where to place this EXP.  Maybe a branch could take the
  form (PATTERN :guard EXP BODY)?
- This forces the guard expressions to be evaluated at the very end,
  so it's a bit less expressive.  In practice this is not too bad, tho.
- There's a similar problem for the (let PAT EXP) pattern, where it
  often/generally has to be coupled with an `and` as in
  (and PAT1 (let PAT EXP)), but this problem can't be solved by moving
  the `let` outside of the pattern like we can for the `guard`.

> This example also shows that `and' has a meaning in pcase that is
> subtly different from its usual meaning in Lisp: `and' in a pcase
> 'UPattern' (as the manual calls it) is not a logical `and' in the
> sense that it tests its arguments for truthiness. Rather, it means
> «both arguments of `and' must apply to the value at this position
> *regardless of truthiness*». (The `and' inside the guard does have the
> usual meaning, of course.)

That's right: the `and` pattern is really an intersection of patterns.


reply via email to

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