[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.