all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* pcase and the unpopular backquote pattern
@ 2019-03-20 20:57 Michael Heerdegen
  2019-03-20 21:40 ` Clément Pit-Claudel
  0 siblings, 1 reply; 3+ messages in thread
From: Michael Heerdegen @ 2019-03-20 20:57 UTC (permalink / raw)
  To: Emacs Development

[-- Attachment #1: Type: text/plain, Size: 75 bytes --]

Hello,

I'm thinking about whether we should install something like this:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-lisp-emacs-lisp-pcase.el-Add-patterns-list-and-list.patch --]
[-- Type: text/x-diff, Size: 2102 bytes --]

From eb8d1f86c744c119ede54cde07a36c1da061c766 Mon Sep 17 00:00:00 2001
From: Michael Heerdegen <michael_heerdegen@web.de>
Date: Wed, 20 Mar 2019 21:21:03 +0100
Subject: [PATCH] * lisp/emacs-lisp/pcase.el: Add patterns list and list*

---
 lisp/emacs-lisp/pcase.el | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index c0a55f3a41..ae45959ff0 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -230,9 +230,10 @@ pcase--make-docstring
                       (when me
                         (push (cons symbol me)
                               more)))))
-        ;; Ensure backquote is first.
-        (let ((x (assq '\` more)))
-          (setq more (cons x (delq x more))))
+        ;; Ensure list stuff is first.
+        (mapc (lambda (m) (let ((x (assq m more)))
+                            (setq more (cons x (delq x more)))))
+              (reverse '(list list* \`)))
         ;; Do the output.
         (while more
           (let* ((pair (pop more))
@@ -1009,5 +1010,24 @@ pcase--u1
    ;; compounded values that are not `consp'
    (t (error "Unknown QPAT: %S" qpat))))

+(pcase-defmacro list (&rest patterns)
+  "Match lists.
+\(list P0 ... Pn-1) matches any list with N elements that are
+matched by patterns P0...Pn-1 in order."
+  `(,'\` ,(mapcar (lambda (pat) `(,'\, ,pat)) patterns)))
+
+(pcase-defmacro list* (&rest patterns)
+  "Match lists with rest.
+\(list* P0 ... Pn-1 R) matches any possibly dotted list with at
+least N elements where the elements with index 0 to N-1 are
+matched by patterns P0...Pn-1 in order, and the list of the
+remaining elements (i.e. the Nth `cdr' of the matched list) is
+matched by pattern R."
+  (unless (cdr patterns)
+    (error "Pattern list* used with less than two arguments"))
+  `(,'\` ,(let* ((l (mapcar (lambda (pat) `(,'\, ,pat)) patterns)))
+            (setcdr (last l 2) (car (last l)))
+            l)))
+
 (provide 'pcase)
 ;;; pcase.el ends here
--
2.20.1


[-- Attachment #3: Type: text/plain, Size: 2728 bytes --]


``' is disliked by some people because its semantics are, while elegant
and consistent, not easy to grasp.  I've got the impression that lots
of people dislike pcase mainly for the backquote patterns.

Given that backquote patterns are used mainly for lists, the suggested
list and list* patterns, analogue to functions list and cl-list*, are
not much less powerful, while their syntax and semantics can be
explained without using recursion.  One disadvantage is that when you
want to destructure nested lists you need to use nested "list" patterns.
I guess for some people that would still be easier to read.  Another
disadvantage would be that we would add completely redundant patterns -
but I don't really see a problem here when it would improve readability
for people.  So, like using the backquote macro only for construction of
complicated nested lists, we would use the backquote pcase pattern only
to construct the complicated patterns needing to perform deeper
destructuring.

A second, minor, reason why I find list and list* patterns useful apart
from that is that it helps to avoid the nested backquote mess you get
when you want to define a pcase macro that expands to a backquote
pattern.

If you for example (just for demonstration, I know this could also be
implemented using 'app') you want to define a pattern 'car' that matches
any cons whose car is matched by a pattern you specify, so for example:

(pcase (list "Hallo" 1 2 3)
  ((car (pred stringp)) t))
==> t.

With list* the definition would look like

(pcase-defmacro car (pat)
  `(list* ,pat _))

while without you would need to write it as

(pcase-defmacro car (pat)
  `(,'\` ((,'\, ,pat) . (,'\, _))))

Not something one needs to do often, but when you need to do that, this
,'\, salad is a pain.

list and list* patterns are themselves expanding to backquote patterns
btw, so they do that work for you in the above case.

Ok, if people want something like that, I could replace at least the
simple (one-level) backquote pcase patterns with equivalent list and
list* forms in the Emacs sources.  What do you think?


Michael.


P.S. BTW, if you wonder why we need two patterns list and list*: that's
because an argument list is not allowed to be a real dotted list, like
in (list 1 2 . 3), which is an invalid expression.  For the same reason
the dot syntax can't be used in pattern "list".  Arguments are allowed
to be dotted lists OTOH, so we could alternatively make it so that the
`list' pattern accepts only one argument, a list of patterns, which is
then allowed to be dotted.  That would be something less intuitive OTOH
and I would expect that it should work recursively as well... and then
it's only one more step and we are back to ``'.

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: pcase and the unpopular backquote pattern
  2019-03-20 20:57 pcase and the unpopular backquote pattern Michael Heerdegen
@ 2019-03-20 21:40 ` Clément Pit-Claudel
  2019-03-20 22:05   ` Michael Heerdegen
  0 siblings, 1 reply; 3+ messages in thread
From: Clément Pit-Claudel @ 2019-03-20 21:40 UTC (permalink / raw)
  To: emacs-devel

On 2019-03-20 16:57, Michael Heerdegen wrote:
> Given that backquote patterns are used mainly for lists, the suggested
> list and list* patterns, analogue to functions list and cl-list*, are
> not much less powerful, while their syntax and semantics can be
> explained without using recursion.  One disadvantage is that when you
> want to destructure nested lists you need to use nested "list" patterns.
> I guess for some people that would still be easier to read.  Another
> disadvantage would be that we would add completely redundant patterns -
> but I don't really see a problem here when it would improve readability
> for people.  

FWIW, I like the backquote pattern :) I don't think I would use this new form, but I don't think it would hurt either (except maybe when people find out that it breaks in old Emacsen).  Also, it would be one more thing to learn when learning pcase.

> With list* the definition would look like
> 
> (pcase-defmacro car (pat)
>   `(list* ,pat _))
> 
> while without you would need to write it as
> 
> (pcase-defmacro car (pat)
>   `(,'\` ((,'\, ,pat) . (,'\, _))))
> 
> Not something one needs to do often, but when you need to do that, this
> ,'\, salad is a pain.

Do you actually need that salad? Isn't the following enough?

(pcase-defmacro car (pat)
  `(\` ((\, ,pat) . (\, _))))




^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: pcase and the unpopular backquote pattern
  2019-03-20 21:40 ` Clément Pit-Claudel
@ 2019-03-20 22:05   ` Michael Heerdegen
  0 siblings, 0 replies; 3+ messages in thread
From: Michael Heerdegen @ 2019-03-20 22:05 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: emacs-devel

Clément Pit-Claudel <cpitclaudel@gmail.com> writes:

> FWIW, I like the backquote pattern :) I don't think I would use this
> new form, but I don't think it would hurt either (except maybe when
> people find out that it breaks in old Emacsen).  Also, it would be one
> more thing to learn when learning pcase.

Yes, I like it too.  You are right that it's more thing to learn.
Dunno, maybe it helps people to get in touch with ``' OTOH?  Removing
``' is not an option for me.


> Do you actually need that salad? Isn't the following enough?
>
> (pcase-defmacro car (pat)
>   `(\` ((\, ,pat) . (\, _))))


Hmm, yes, it was a really bad example.  Even this is ok:

(pcase-defmacro car (pat)
  ``(,,pat . ,_))

AFAIR there are cases where you need an unquote-backquote combination,
but it doesn't matter much anyway.


Michael.



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-03-20 22:05 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-03-20 20:57 pcase and the unpopular backquote pattern Michael Heerdegen
2019-03-20 21:40 ` Clément Pit-Claudel
2019-03-20 22:05   ` Michael Heerdegen

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.