* EXPVAL in pcase-defmacro docstrings @ 2018-05-30 12:28 Stefan Monnier 2018-05-31 14:56 ` Thien-Thi Nguyen 0 siblings, 1 reply; 3+ messages in thread From: Stefan Monnier @ 2018-05-30 12:28 UTC (permalink / raw To: Thien-Thi Nguyen; +Cc: emacs-devel I think this change is misguided: - When reading source code, you get things like: (pcase-defmacro radix-tree-leaf (vpat) "Build a `pcase' pattern that matches radix-tree leaf EXPVAL. VPAT is a `pcase' pattern to extract the value." where the EXPVAL comes out of nowhere - The wording "matches radix-tree leaf EXPVAL" makes it sound like the reader is already familiar with EXPVAL and that we know already that it's a radix-tree leaf, whereas the pattern will have to check if EXPVAL is such a leaf. - In the pcase docstring, EXPVAL refers to the "toplevel" value, so when we say things like 'VAL matches if EXPVAL is `equal' to VAL. it makes it sound like (cons '1 '2) will not match against the value (1 . 2) because EXPVAL is (1 . 2) and '1 is not `equal` to (1 . 2). - The "standard" way to describe a pattern is to say things like (fumble-tree E1 E2) matches fumble-trees E.g. _ matches anything SYMBOL matches anything and binds it to SYMBOL. (guard BOOLEXP) matches if BOOLEXP evaluates to non-nil. (let PAT EXPR) matches if EXPR matches PAT. (and PAT...) matches if all the patterns match. (or PAT...) matches if any of the patterns matches. While it may occasionally be handy to be able to refer to EXPVAL, for example in (app FUN PAT) matches if FUN called on EXPVAL matches PAT. I believe the standard terminology is to say "the target" instead of EXPVAL. For example, I think the patch below would improve the doc. Stefan diff --git a/lisp/emacs-lisp/radix-tree.el b/lisp/emacs-lisp/radix-tree.el index 2491ccea95..6a11977782 100644 --- a/lisp/emacs-lisp/radix-tree.el +++ b/lisp/emacs-lisp/radix-tree.el @@ -196,8 +196,8 @@ radix-tree-prefixes (eval-and-compile (pcase-defmacro radix-tree-leaf (vpat) - "Build a `pcase' pattern that matches radix-tree leaf EXPVAL. -VPAT is a `pcase' pattern to extract the value." + "Pattern which matches a radix-tree leaf. +The pattern VPAT is matched against the leaf's carried value." ;; FIXME: We'd like to use a negative pattern (not consp), but pcase ;; doesn't support it. Using `atom' works but generates sub-optimal code. `(or `(t . ,,vpat) (and (pred atom) ,vpat)))) diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el index fa7b1de8b4..0ba0d75776 100644 --- a/lisp/emacs-lisp/pcase.el +++ b/lisp/emacs-lisp/pcase.el @@ -119,7 +119,7 @@ pcase PATTERN matches. PATTERN can take one of the forms: _ matches anything. - \\='VAL matches if EXPVAL is `equal' to VAL. + \\='VAL matches objects `equal' to VAL. KEYWORD shorthand for \\='KEYWORD INTEGER shorthand for \\='INTEGER STRING shorthand for \\='STRING ^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: EXPVAL in pcase-defmacro docstrings 2018-05-30 12:28 EXPVAL in pcase-defmacro docstrings Stefan Monnier @ 2018-05-31 14:56 ` Thien-Thi Nguyen 2018-06-04 14:43 ` Stefan Monnier 0 siblings, 1 reply; 3+ messages in thread From: Thien-Thi Nguyen @ 2018-05-31 14:56 UTC (permalink / raw To: Stefan Monnier; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 4582 bytes --] () Stefan Monnier <monnier@IRO.UMontreal.CA> () Wed, 30 May 2018 08:28:29 -0400 I think this change is misguided: - When reading source code, you get things like: (pcase-defmacro radix-tree-leaf (vpat) "Build a `pcase' pattern that matches radix-tree leaf EXPVAL. VPAT is a `pcase' pattern to extract the value." where the EXPVAL comes out of nowhere - The wording "matches radix-tree leaf EXPVAL" makes it sound like the reader is already familiar with EXPVAL and that we know already that it's a radix-tree leaf, whereas the pattern will have to check if EXPVAL is such a leaf. Yes. That is awkward, when reading the source code. Thanks for pointing it out; i was focusing on the aggregated docstring for that change. For docstrings where it makes sense to use EXPVAL (maybe not this one), how about we add a small comment pointing to the EXPVAL convention? That way, we retain consistency in the presentation (for ‘C-h f pcase RET’), and give a clue to people who read source code. I say "maybe" because, in trying to better understand the operation of ‘radix-tree-leaf’, i found this comment puzzling: ;; FIXME: We'd like to use a negative pattern (not consp), ;; but pcase doesn't support it. Using `atom' works but ;; generates sub-optimal code. `(or `(t . ,,vpat) (and (pred atom) ,vpat)))) Does that mean we'd want a hypothetical ‘(pred (not consp))’ if such a construct were supported by ‘pcase’? Another question i have concerns ‘(t . ...)’. My understanding is that in a structural pattern (that begins with backquote), a symbol represents itself. However, IIUC the car of the nodes is always a string. So this subpattern never matches. Experimenting in *scratch*, i see: (let ((tr radix-tree-empty) sub) (setq tr (radix-tree-insert tr "all" 0) tr (radix-tree-insert tr "abc" 99) tr (radix-tree-insert tr "abx" 2) sub (radix-tree-subtree tr "a")) (list :sub sub :etc (pcase sub ((radix-tree-leaf v) v)))) => (:sub (("ll" . 0) ("b" ("c" . 99) ("x" . 2))) :etc nil) However, if i define ‘radix-tree-leaf-NEW’ as follows: (eval-and-compile (pcase-defmacro radix-tree-leaf-NEW (vpat) `(or `(,_ . ,,vpat) (and (pred atom) ,vpat)))) replacing ‘t’ w/ ‘,_’ (comma underscore) to "match anything", i see instead: (let ((tr radix-tree-empty) sub) (setq tr (radix-tree-insert tr "all" 0) tr (radix-tree-insert tr "abc" 99) tr (radix-tree-insert tr "abx" 2) sub (radix-tree-subtree tr "a")) (list :sub sub :etc (pcase sub ((radix-tree-leaf-NEW v) v)))) => (:sub (("ll" . 0) ("b" ("c" . 99) ("x" . 2))) :etc (("b" ("c" . 99) ("x" . 2)))) Thinking about this a bit more, i suppose the comment makes sense if the intention of using ‘t’ is to never match. Since ‘pcase’ supports lambda expressions for the ‘pred’ pattern, we can use one directly: (pred (lambda (x) (not (consp x)))) and then simplify the definition to something like: (eval-and-compile (pcase-defmacro radix-tree-leaf-NEW-2 (vpat) `(and (pred (lambda (x) (not (consp x)))) ,vpat))) Another idea is to make ‘pcase’ support a new core pattern, say "npred", which would be similar to ‘pred’ but invert the result of the predicate it uses. Here, it would be: ‘(npred consp)’. If this interpretation is correct, i would also suggest another change: from VPAT to VAR. This would emphasize that VAR is the usual vehicle for binding the leaf node "data" for use in the clause's body forms. (Maybe "usual" is stretching it -- i found only one use of ‘radix-tree-leaf’ in the Emacs 26 repo.) Using VAR would be easier to document, too. Anyway, the documentation can say "VAR can also be a pcase pattern", so as not preclude more complex usage. WDYT? I'll respond to the remaining points in the next mail. -- Thien-Thi Nguyen ----------------------------------------------- (defun responsep (query) ; (2018) Software Libero (pcase (context query) ; = Dissenso Etico (`(technical ,ml) (correctp ml)) ...)) 748E A0E8 1CB8 A748 9BFA --------------------------------------- 6CE4 6703 2224 4C80 7502 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: EXPVAL in pcase-defmacro docstrings 2018-05-31 14:56 ` Thien-Thi Nguyen @ 2018-06-04 14:43 ` Stefan Monnier 0 siblings, 0 replies; 3+ messages in thread From: Stefan Monnier @ 2018-06-04 14:43 UTC (permalink / raw To: emacs-devel > Yes. That is awkward, when reading the source code. Thanks for > pointing it out; i was focusing on the aggregated docstring for > that change. For docstrings where it makes sense to use EXPVAL > (maybe not this one), how about we add a small comment pointing > to the EXPVAL convention? That way, we retain consistency in > the presentation (for ‘C-h f pcase RET’), and give a clue to > people who read source code. As mentioned, I think "target" is the standard terminology, so we could use that. Of course, there might be cases where EXPVAL would work better, but I don't think we need to encourage people to use EXPVAL nor to decide how best to use it when it makes sense because it will likely depend on the specifics. > ;; FIXME: We'd like to use a negative pattern (not consp), > ;; but pcase doesn't support it. Using `atom' works but > ;; generates sub-optimal code. > `(or `(t . ,,vpat) (and (pred atom) ,vpat)))) > > Does that mean we'd want a hypothetical ‘(pred (not consp))’ if > such a construct were supported by ‘pcase’? The idea was to use `(or `(t . ,,vpat) (and (not (pred consp)) ,vpat)))) Strictly speaking I'm very happy with the appearance of the current code, the comment is only about the resulting macroexpansion because pcase doesn't understand that (atom X) and (consp X) are mutually exclusive. But you're right that maybe a halfway solution would be `(or `(t . ,,vpat) (and (pred (not consp)) ,vpat)))) which might be much easier to implement (in the sense that it might be reasonably easy to add code to the handling of `pred` so it treats negation efficiently). > Another question i have concerns ‘(t . ...)’. My understanding This is used for leaves whose *value* is itself a `cons`. E.g. compare (radix-tree-insert nil "ab" '42) and (radix-tree-insert nil "ab" '(42)) So indeed the `t` is used because it's not a string so it shouldn't match any normal code's `car`. Stefan ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2018-06-04 14:43 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-05-30 12:28 EXPVAL in pcase-defmacro docstrings Stefan Monnier 2018-05-31 14:56 ` Thien-Thi Nguyen 2018-06-04 14:43 ` Stefan Monnier
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.