emacs-devel
[Top][All Lists]
Advanced

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

Re: "Like `let*' but ....."


From: Michael Heerdegen
Subject: Re: "Like `let*' but ....."
Date: Wed, 25 Jan 2017 00:10:11 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux)

Hello Alan,

> The doc string of pcase-let* reads, in its entirety:
>
>        "Like `let*' but where you can use `pcase' patterns for bindings.
>     BODY should be an expression, and BINDINGS should be a list of bindings
>     of the form (PAT EXP)."
>
> What is not clear is precisely HOW `pcase' patterns are used for
> bindings, and what the semantics of (PAT EXP) are.

I think Clément's has answered that correctly.  And for the semantics of
the patterns see C-h f pcase.


> What eludes me is points such as:
> (i) what variables are being bound?
> (ii) To what values?
> (iii) What do the `or's and `and's on Line 4, etc. mean?

If you are interested in learning to understand `pcase' patterns: if you
want to test what effect matching a pattern against some value has, I
had written the following thing some time ago:

#+begin_src emacs-lisp

(defun my-pcase-matcher (pattern)
  "Turn pcase PATTERN into a predicate.
For any given pcase PATTERN, return a predicate P that returns
non-nil for any EXP when and only when PATTERN matches EXP.  In
that case, P returns a list of the form (bindings . BINDINGS) as
non-nil value, where BINDINGS is a list of bindings that pattern
matching would actually establish in a pcase branch.

Example:

  (setq matcher
        (my-pcase-matcher
         '`(,(and (pred integerp) x)
            ,(and (pred integerp)
                  (pred (< 0))
                  y))))

  (funcall matcher '(1 0))
    ==> nil

  (funcall matcher '(1 2))

    ==>
   (bindings
    (x . 1)
    (y . 2))"
  (let ((arg  (make-symbol "exp")))
    `(lambda (,arg)
       ,(pcase--u
         `((,(pcase--match arg (pcase--macroexpand pattern))
            ,(lambda (vars)
               `(list
                 'bindings
                 ,@(nreverse
                    (mapcar (lambda (pair) `(cons ',(car pair) ,(cdr pair)))
                            vars))))))))))
#+end_src


> Incidentally, when I expand that form with macroexpand-all and print it
> with pp, the resulting form is 173 lines long, totally inscrutable, a
> typical portion of it looking like this: 
>
>                                           (if
>                                               (null x)
>                                               (let*
>                                                   ((x
>                                                     (cdr x)))

Note that you should bind print-circle -> t and print-gensym -> t when
printing to get a semantically equivalent printed representation of the
macroexpansion.


> Is this efficient, in either run-time or the size of the byte code
> produced?

Those highly nested expressions come from destructuring.  I think the
expansion is nearly as effecient as it could be.  Dunno about the byte
code size.


Regards,

Michael.



reply via email to

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