unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* map.el: pcase plist keyword-only binding improvement
@ 2020-02-02  9:37 Adam Porter
  2020-02-02 13:46 ` Stefan Monnier
  0 siblings, 1 reply; 6+ messages in thread
From: Adam Porter @ 2020-02-02  9:37 UTC (permalink / raw)
  To: emacs-devel

Hi,

One of the features I find very useful in dash.el's `-let' macro is its
ability to bind plist values to variables of the same names as the keys.
With map.el's `pcase' support, Emacs's `pcase' and `pcase-let' can do
this as well, but in a less convenient way, because it requires writing
both the keyword and the variable name.

However, with a simple change to one of map'el's functions, it can
support keyword-only plist binding as well.

Example usage before change:

#+BEGIN_SRC elisp
  (let ((pl '(:one 1 :two 2)))
    (pcase pl
      ((map :one (:two two))
       (list one two))))  ;;=> nil

  (pcase-let* (((map :one (:two two))
                '(:one 1 :two 2)))
    (list one two)) ;;=> (void-variable one)
#+END_SRC

Changed function:

#+BEGIN_SRC elisp
  (defun map--make-pcase-bindings (args)
    "Return a list of pcase bindings from ARGS to the elements of a map."
    (seq-map (lambda (elt)
               (cond ((consp elt)
                      `(app (pcase--flip map-elt ,(car elt)) ,(cadr elt)))
                     ((keywordp elt)
                      ;; New clause for keyword-only elements.
                      (let ((var (intern (substring (symbol-name elt) 1))))
                        `(app (pcase--flip map-elt ,elt) ,var)))
                     (t
                      `(app (pcase--flip map-elt ',elt) ,elt))))
             args))
#+END_SRC

Example usage after change:

#+BEGIN_SRC elisp
  (let ((pl '(:one 1 :two 2)))
    (pcase pl
      ((map :one (:two two))
       (list one two)))) ;;=> (1 2)

  (pcase-let* (((map :one (:two two))
                '(:one 1 :two 2)))
    (list one two)) ;;=> (1 2)
#+END_SRC

Assuming that this change is acceptable, I would like to prepare a
patch, which would probably need to include NEWS and documentation
changes.  However, since the change is to map.el rather than pcase.el,
and since map.el is also available on ELPA, I'm not sure how to proceed
with those parts, where to make the appropriate documentation changes,
etc.

Please let me know if this proposal is acceptable and how I should
proceed.

Thanks,
Adam




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

* Re: map.el: pcase plist keyword-only binding improvement
  2020-02-02  9:37 map.el: pcase plist keyword-only binding improvement Adam Porter
@ 2020-02-02 13:46 ` Stefan Monnier
  2020-02-02 16:38   ` Adam Porter
  0 siblings, 1 reply; 6+ messages in thread
From: Stefan Monnier @ 2020-02-02 13:46 UTC (permalink / raw)
  To: Adam Porter; +Cc: emacs-devel

>     (seq-map (lambda (elt)
>                (cond ((consp elt)
>                       `(app (pcase--flip map-elt ,(car elt)) ,(cadr elt)))
>                      ((keywordp elt)
>                       ;; New clause for keyword-only elements.
>                       (let ((var (intern (substring (symbol-name elt) 1))))
>                         `(app (pcase--flip map-elt ,elt) ,var)))
>                      (t
>                       `(app (pcase--flip map-elt ',elt) ,elt))))
>              args))

Since binding the result of the match to a keyword can't work anyway,
this seems like a very good idea.

> Assuming that this change is acceptable, I would like to prepare a
> patch, which would probably need to include NEWS and documentation
> changes.

AFAICT we don't yet have actual documentation for the map.el package, so
only NEWS needs to be changed.

> However, since the change is to map.el rather than pcase.el,
> and since map.el is also available on ELPA,

It's also distributed via GNU ELPA indeed, but taken straight from the
emacs.git repository, so you don't need to worry about that (just
increment the `Version:` entry at the top).


        Stefan




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

* Re: map.el: pcase plist keyword-only binding improvement
  2020-02-02 13:46 ` Stefan Monnier
@ 2020-02-02 16:38   ` Adam Porter
       [not found]     ` <874kw86dft.fsf@web.de>
  2020-02-04 17:30     ` Stefan Monnier
  0 siblings, 2 replies; 6+ messages in thread
From: Adam Porter @ 2020-02-02 16:38 UTC (permalink / raw)
  To: emacs-devel

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

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>>     (seq-map (lambda (elt)
>>                (cond ((consp elt)
>>                       `(app (pcase--flip map-elt ,(car elt)) ,(cadr elt)))
>>                      ((keywordp elt)
>>                       ;; New clause for keyword-only elements.
>>                       (let ((var (intern (substring (symbol-name elt) 1))))
>>                         `(app (pcase--flip map-elt ,elt) ,var)))
>>                      (t
>>                       `(app (pcase--flip map-elt ',elt) ,elt))))
>>              args))
>
> Since binding the result of the match to a keyword can't work anyway,
> this seems like a very good idea.
>
>> Assuming that this change is acceptable, I would like to prepare a
>> patch, which would probably need to include NEWS and documentation
>> changes.
>
> AFAICT we don't yet have actual documentation for the map.el package, so
> only NEWS needs to be changed.
>
>> However, since the change is to map.el rather than pcase.el,
>> and since map.el is also available on ELPA,
>
> It's also distributed via GNU ELPA indeed, but taken straight from the
> emacs.git repository, so you don't need to worry about that (just
> increment the `Version:` entry at the top).

Hi Stefan,

Ok, I've attached a patch.  I tried to follow the appropriate
guidelines, but please let me know if any changes are required.

Thanks,
Adam

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: map.el keyword-only pattern abbreviation --]
[-- Type: text/x-diff, Size: 3465 bytes --]

From d5cb310d6fb30e2991a94e433b754c07893133ef Mon Sep 17 00:00:00 2001
From: Adam Porter <adam@alphapapa.net>
Date: Sun, 2 Feb 2020 10:17:20 -0600
Subject: [PATCH] * lisp/emacs-lisp/map.el: Add keyword-only pattern
 abbreviation

* lisp/emacs-lisp/map.el: Update version to 2.1.
((pcase-defmacro map)): Update docstring.
(map--make-pcase-bindings): Match keyword pattern.

* test/lisp/emacs-lisp/map-tests.el (test-map-plist-pcase): Add test.
---
 etc/NEWS                          |  6 ++++++
 lisp/emacs-lisp/map.el            | 17 +++++++++++------
 test/lisp/emacs-lisp/map-tests.el |  6 ++++++
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 2b9337b..7444166 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -107,6 +107,12 @@ supplied error message.
 *** New connection method "media", which allows accessing media devices
 like cell phones, tablets or cameras.
 
+** map.el
+
+*** Pcase 'map' pattern added keyword symbols abbreviation.
+A pattern like '(map :sym)' binds the map's value for ':sym' to 'sym',
+equivalent to '(map (:sym sym))'.
+
 \f
 * New Modes and Packages in Emacs 28.1
 
diff --git a/lisp/emacs-lisp/map.el b/lisp/emacs-lisp/map.el
index 67f5b3c..9c23344 100644
--- a/lisp/emacs-lisp/map.el
+++ b/lisp/emacs-lisp/map.el
@@ -4,7 +4,7 @@
 
 ;; Author: Nicolas Petton <nicolas@petton.fr>
 ;; Keywords: convenience, map, hash-table, alist, array
-;; Version: 2.0
+;; Version: 2.1
 ;; Package-Requires: ((emacs "25"))
 ;; Package: map
 
@@ -56,8 +56,10 @@ evaluated and searched for in the map.  The match fails if for any KEY
 found in the map, the corresponding PAT doesn't match the value
 associated to the KEY.
 
-Each element can also be a SYMBOL, which is an abbreviation of a (KEY
-PAT) tuple of the form (\\='SYMBOL SYMBOL).
+Each element can also be a SYMBOL, which is an abbreviation of
+a (KEY PAT) tuple of the form (\\='SYMBOL SYMBOL).  When SYMBOL
+is a keyword, it is an abbreviation of the form (:SYMBOL SYMBOL),
+useful for binding plist values.
 
 Keys in ARGS not found in the map are ignored, and the match doesn't
 fail."
@@ -486,9 +488,12 @@ Example:
 (defun map--make-pcase-bindings (args)
   "Return a list of pcase bindings from ARGS to the elements of a map."
   (seq-map (lambda (elt)
-             (if (consp elt)
-                 `(app (pcase--flip map-elt ,(car elt)) ,(cadr elt))
-               `(app (pcase--flip map-elt ',elt) ,elt)))
+             (cond ((consp elt)
+                    `(app (pcase--flip map-elt ,(car elt)) ,(cadr elt)))
+                   ((keywordp elt)
+                    (let ((var (intern (substring (symbol-name elt) 1))))
+                      `(app (pcase--flip map-elt ,elt) ,var)))
+                   (t `(app (pcase--flip map-elt ',elt) ,elt))))
            args))
 
 (defun map--make-pcase-patterns (args)
diff --git a/test/lisp/emacs-lisp/map-tests.el b/test/lisp/emacs-lisp/map-tests.el
index 06fd55f..3ffef17 100644
--- a/test/lisp/emacs-lisp/map-tests.el
+++ b/test/lisp/emacs-lisp/map-tests.el
@@ -376,5 +376,11 @@ Evaluate BODY for each created map.
                                  '((1 . 1) (2 . 5) (3 . 0)))
                  '((3 . 0) (2 . 9) (1 . 6)))))
 
+(ert-deftest test-map-plist-pcase ()
+  (let ((plist '(:one 1 :two 2)))
+    (should (equal (pcase-let (((map :one (:two two)) plist))
+                     (list one two))
+                   '(1 2)))))
+
 (provide 'map-tests)
 ;;; map-tests.el ends here
-- 
2.7.4


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

* Re: map.el: pcase plist keyword-only binding improvement
       [not found]     ` <874kw86dft.fsf@web.de>
@ 2020-02-03 15:02       ` Nicolas Petton
  0 siblings, 0 replies; 6+ messages in thread
From: Nicolas Petton @ 2020-02-03 15:02 UTC (permalink / raw)
  To: Michael Heerdegen, Adam Porter; +Cc: Emacs Devel

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

Michael Heerdegen <michael_heerdegen@web.de> writes:

> Hi Adam,

Hi Michael, Adam,

> I'm just CC'ing (offlist) Nicolas Petton, the author of map.el, who
> wanted to be kept informed about changes.  Please give him a few days
> and keep him CC'd in the discussion in emacs-dev.  He used to be short
> on time so it can happen he doesn't chime in.

Thanks for keeping me posted.

The change looks good, thanks!

Cheers,
Nico

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

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

* Re: map.el: pcase plist keyword-only binding improvement
  2020-02-02 16:38   ` Adam Porter
       [not found]     ` <874kw86dft.fsf@web.de>
@ 2020-02-04 17:30     ` Stefan Monnier
  2020-02-04 22:31       ` Adam Porter
  1 sibling, 1 reply; 6+ messages in thread
From: Stefan Monnier @ 2020-02-04 17:30 UTC (permalink / raw)
  To: Adam Porter; +Cc: emacs-devel

> Ok, I've attached a patch.  I tried to follow the appropriate
> guidelines, but please let me know if any changes are required.

Looks good, thanks, pushed,


        Stefan




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

* Re: map.el: pcase plist keyword-only binding improvement
  2020-02-04 17:30     ` Stefan Monnier
@ 2020-02-04 22:31       ` Adam Porter
  0 siblings, 0 replies; 6+ messages in thread
From: Adam Porter @ 2020-02-04 22:31 UTC (permalink / raw)
  To: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> Looks good, thanks, pushed,

Thanks!




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

end of thread, other threads:[~2020-02-04 22:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-02  9:37 map.el: pcase plist keyword-only binding improvement Adam Porter
2020-02-02 13:46 ` Stefan Monnier
2020-02-02 16:38   ` Adam Porter
     [not found]     ` <874kw86dft.fsf@web.de>
2020-02-03 15:02       ` Nicolas Petton
2020-02-04 17:30     ` Stefan Monnier
2020-02-04 22:31       ` Adam Porter

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).