unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Stefan Monnier <monnier@iro.umontreal.ca>
To: "Mattias Engdegård" <mattiase@acm.org>
Cc: "Basil L. Contovounesios" <contovob@tcd.ie>,
	Ag Ibragimov <agzam.ibragimov@gmail.com>,
	emacs-devel@gnu.org
Subject: Re: Pattern matching on match-string groups #elisp #question
Date: Thu, 25 Feb 2021 23:31:14 -0500	[thread overview]
Message-ID: <jwvft1jeahy.fsf-monnier+emacs@gnu.org> (raw)
In-Reply-To: <80CE2366-76F4-4548-B956-F16DFCE23E4C@acm.org> ("Mattias Engdegård"'s message of "Thu, 25 Feb 2021 19:28:16 +0100")

>> 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	other threads:[~2021-02-26  4:31 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-25  5:11 Pattern matching on match-string groups #elisp #question Ag Ibragimov
2021-02-25 14:55 ` Basil L. Contovounesios
2021-02-25 15:32   ` Stefan Monnier
2021-02-25 18:28     ` Mattias Engdegård
2021-02-26  4:31       ` Stefan Monnier [this message]
2021-02-26 10:24         ` Mattias Engdegård
2021-02-26 19:38           ` Stefan Monnier
2021-02-27 10:17             ` Mattias Engdegård
2021-02-27 14:39               ` Stefan Monnier
2021-02-27 18:10                 ` Mattias Engdegård
2021-02-27 20:32                   ` Stefan Monnier
2021-02-28 13:46                     ` Mattias Engdegård
2021-02-28 15:37                       ` Stefan Monnier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=jwvft1jeahy.fsf-monnier+emacs@gnu.org \
    --to=monnier@iro.umontreal.ca \
    --cc=agzam.ibragimov@gmail.com \
    --cc=contovob@tcd.ie \
    --cc=emacs-devel@gnu.org \
    --cc=mattiase@acm.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).