emacs-devel
[Top][All Lists]
Advanced

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

Re: Pattern matching on match-string groups #elisp #question


From: Stefan Monnier
Subject: Re: Pattern matching on match-string groups #elisp #question
Date: Thu, 25 Feb 2021 23:31:14 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

>> I'd say it's a bug.  The patch below would fix it.  Mattias, WDYT?
> Thank you, it looks like multiple bugs.  The lack of (pred stringp) was of
> course an oversight but unrelated to pcase-let, right?

Yes, it's unrelated.  I just noticed it along the way.

>>   (let* ((rx--pcase-vars nil)
>>          (regexp (rx--to-expr (rx--pcase-transform (cons 'seq regexps)))))
>> -    `(and (pred (string-match ,regexp))
>> +    `(and (pred stringp)
>> +          (app (lambda (s) (string-match ,regexp s)) (pred identity))
> It does seem to work, but why exactly do we need this monstrosity instead of
> (pred (string-match ,regexp))?

Good question.  I'm not sure how best to explain or document it, sadly.
One of the reasons is that predicates are presumed to be (mostly) pure
functions, so `pcase` feels free to call them fewer times or more times
as it pleases.

But that also largely applies to `app`, so that's not a very
good explanation.

Maybe a better explanation is that `pcase-let` optimizes the pattern
match code under the assumption that the pattern will match, so it skips
the tests that determine whether the pattern matches or not.

[ That doesn't mean it skips all the tests: if the pattern is
  (or `(a ,v) `(b ,_ ,v)) it *will* test to see if the first element is `a` in
  order to decide what to bind `v` to, but it won't bother to check if
  the first element is `b` since it presumes that the pattern does match
  and it knows that there's no further alternative.  ]

Note that this explanation is not very convincing either because it's
not clear if the test that it skipped is `(identity VAR)`
or `(identity (string-match ...))` so it's unclear whether the
`string-match` is eliminated.

> Is it because pcase-let throws away all `pred` clauses somewhere?
> It makes sense to do so but I haven't found exactly where this takes
> place in pcase.el yet...

The magic is in `pcase--if`.  I.e. a lower-level than `pred`.
It's linked to the special undocumented pcase pattern `pcase--dontcare`
(whose name is not well chosen, suggestions for better names are
welcome) which is a pattern that not only can never match but also
prevents pcase from attempting to match any further patterns (IOW it
forces pcase to just go with the last branch that it failed to match).

You might also want to look at `byte-optimize--pcase` for another
example where I use this pattern.

> Perhaps the assumption that non-binding clauses like `pred` (and what else,
> `guard`?) are all side-effect free and can be thrown away in pcase-let[*]
> should be documented?

Agreed.

> Not that I would have read it, of course...

At least I'd get to point you to the doc and shame you publicly.

> I'll push a fix as soon as I understand the machinery a bit better, but
> right now I'm wary of getting my fingers snapped off by the gears
> and knives.

Come on, that's why we start with ten of those damn fingers.  You surely
can still afford to risk one or two.


        Stefan




reply via email to

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