[Top][All Lists]

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

Re: Using gv in map and seq?

From: Stefan Monnier
Subject: Re: Using gv in map and seq?
Date: Mon, 15 Jun 2015 12:30:03 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux)

>>> I was wondering if it would make sense to use gv in map or seq?
>> Not sure what you mean.  Do you mean to add a setter for seq-elt?
> Yes

I see.  Yes, defining a "gv-setter" or "gv-expander" would be good.

Oh, wait, no, it's not needed, since seq-elt is an alias for `elt' and
that one already has a setter.  IOW it already works!

> (and a getter too?).

When defining a setter, you need to define the getter as well, indeed, but
that's generally the trivial part.

> The same goes for `map-elt'.

This one is not pre-defined, so yes, we should define it.
Actually, this just means to turn map-put into a gv-setter.

Something like the patch below seems to work (and it generalizes
map-put to accept for MAP not only symbols but any "lvalue").  It also
tightens the code generated by map--dispatch.


diff --git a/lisp/emacs-lisp/map.el b/lisp/emacs-lisp/map.el
index dd7fb91..26ad6ce 100644
--- a/lisp/emacs-lisp/map.el
+++ b/lisp/emacs-lisp/map.el
@@ -82,25 +82,19 @@ The following keyword types are meaningful: `:list',
 An error is thrown if MAP is neither a list, hash-table nor array.
-Return RESULT if non-nil or the result of evaluation of the
+Return RESULT if non-nil or the result of evaluation of the form.
 \(fn (VAR MAP [RESULT]) &rest ARGS)"
   (declare (debug t) (indent 1))
   (unless (listp spec)
     (setq spec `(,spec ,spec)))
-  (let ((map-var (car spec))
-        (result-var (make-symbol "result")))
-    `(let ((,map-var ,(cadr spec))
-           ,result-var)
-       (setq ,result-var
-             (cond ((listp ,map-var) ,(plist-get args :list))
-                   ((hash-table-p ,map-var) ,(plist-get args :hash-table))
-                   ((arrayp ,map-var) ,(plist-get args :array))
-                   (t (error "Unsupported map: %s" ,map-var))))
-       ,@(when (cddr spec)
-           `((setq ,result-var ,@(cddr spec))))
-       ,result-var)))
+  (let ((map-var (car spec)))
+    `(let* ,(unless (eq map-var (cadr spec)) `((,map-var ,(cadr spec))))
+       (cond ((listp ,map-var) ,(plist-get args :list))
+             ((hash-table-p ,map-var) ,(plist-get args :hash-table))
+             ((arrayp ,map-var) ,(plist-get args :array))
+             (t (error "Unsupported map: %s" ,map-var)))
+       ,@(cddr spec))))
 (defun map-elt (map key &optional default)
   "Perform a lookup in MAP of KEY and return its associated value.
@@ -109,27 +103,23 @@ If KEY is not found, return DEFAULT which defaults to nil.
 If MAP is a list, `equal' is used to lookup KEY.
 MAP can be a list, hash-table or array."
+  (declare
+   (gv-expander
+    (lambda (do)
+      (macroexp-let2* nil
+          ;; Eval them once and for all in the right order.
+          ((map map) (key key) (default default))
+        `(map--dispatch map
+           :list ,(gv-get `(alist-get ,key ,map ,default) do)
+           :hash-table ,(funcall do `(gethash ,key ,map ,default)
+                                 (lambda (v) `(puthash ,key ,v ,map)))
+           :array ,(funcall do `(aref ,map ,key)
+                            (lambda (v) `(aset ,map ,key ,v))))))))
   (map--dispatch map
     :list (map--elt-list map key default)
     :hash-table (gethash key map default)
     :array (map--elt-array map key default)))
-(defmacro map-put (map key value)
-  "In MAP, associate KEY with VALUE and return MAP.
-If KEY is already present in MAP, replace the associated value
-with VALUE.
-MAP can be a list, hash-table or array."
-  (declare (debug t))
-  (let ((symbol (symbolp map)))
-    `(progn
-       (map--dispatch (m ,map m)
-         :list (if ,symbol
-                   (setq ,map (cons (cons ,key ,value) m))
-                 (error "Literal lists are not allowed, %s must be a symbol" 
-         :hash-table (puthash ,key ,value m)
-         :array (aset m ,key ,value)))))
 (defmacro map-delete (map key)
   "In MAP, delete the key KEY if present and return MAP.
 If MAP is an array, store nil at the index KEY.

reply via email to

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