emacs-devel
[Top][All Lists]
Advanced

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

Re: Instead of pcase


From: Yuri Khan
Subject: Re: Instead of pcase
Date: Tue, 21 Nov 2023 12:34:51 +0700

On Tue, 21 Nov 2023 at 09:42, Richard Stallman <rms@gnu.org> wrote:
>   > To interpret those backquotes and commas, one can imagine that the they
>   > do the inverse of the usual.
>
> I uderstand that when you say it, but when I saw the line
>
> >          > (`(,hookfun . (,start ,end ,collection . ,plist))
>
> I was not sure which part of the line that rule applies to.
>
> In particular, what is the reason for the period and inner
> parenthsses?  Why doesn't the code say this?
>
> >          > (`(,hookfun ,start ,end ,collection . ,plist)
>
> Would that be equiva;ent?

I am looking at this part of code for the first time so let’s see what
I can make of it.

The code in the revision I’m looking at looks like this:

    (defun completion-at-point ()
      "…"
      (interactive)
      (let ((res (run-hook-wrapped 'completion-at-point-functions
                                   #'completion--capf-wrapper 'all)))
        (pcase res
          (`(,_ . ,(and (pred functionp) f)) (funcall f))
          (`(,hookfun . (,start ,end ,collection . ,plist))
           …)
          ;; Maybe completion already happened and the function returned t.
          (_
           …))))

First, this runs a hook and binds its returned value to the local name ‘res’.

Then it matches that value to one of three patterns, the last of which
is a match-all. The first two look like they match ‘res’ to a cons
cell. I go to look a the documentation of
‘completion-at-point-functions’:

    should return either nil, meaning it is not applicable at point,
    or a function of no arguments to perform completion (discouraged),
    or a list of the form (START END COLLECTION . PROPS), where:

Aha! The two latter formats are the same as the inner matchers in the
first two pcase alternatives. I look at ‘completion--capf-wrapper’ to
see if it supplies the ‘car’ part.

    (defun completion--capf-wrapper (fun which)
      (if …
          (let ((res (funcall fun)))
             …
             (if res (cons fun res)))))

It seems it does! So the pcase matchers in ‘completion-at-point’ are
written that way because the wrapper returns a cons cell with the
function in car and its result in cdr, and one of the possible formats
of the result is a sub-list.

I’m pretty sure collapsing that `(,hookfun . (,start …)) to `(,hookfun
,start …) would be an equivalent transformation, but I also feel it
would mash together the expectations from the wrapper and the
completion-at-point function thus increasing cognitive load for the
reader.


I further notice that, curiously, the inside of
‘completion--capf-wrapper’ analyses the result of (funcall fun) with a
cond, consp, listp, functionp, and nthcdr 3 to check some conditions,
then extracts its car, nth 2, and nthcdr 3 to pass them to a nested
‘try-completion’ call, and it’s not trivial for me to follow as I have
to keep in mind the general structure of the list. If I were trying to
grok that function, I would, for personal reference, try to rewrite it
to pcase, binding the parts of the list to descriptive names.



reply via email to

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