[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
defmacro with built-in gensym declaration and initialization
From: |
akater |
Subject: |
defmacro with built-in gensym declaration and initialization |
Date: |
Wed, 20 Jan 2021 08:15:46 +0000 |
I suggest extending ~defmacro~ to support ~&gensym~ keyword in its
lambda list, for convenient declaration and initialization of gensyms.
Below there's a link to working implementation, and to specification.
A realistic example from popular package =dash=
#+begin_example emacs-lisp
(defmacro --partition-by (form list)
"Anaphoric form of `-partition-by'."
(declare (debug (form form)))
(let ((r (make-symbol "result"))
(s (make-symbol "sublist"))
(v (make-symbol "value"))
(n (make-symbol "new-value"))
(l (make-symbol "list")))
`(let ((,l ,list))
(when ,l
(let* ((,r nil)
(it (car ,l))
(,s (list it))
(,v ,form)
(,l (cdr ,l)))
(while ,l
(let* ((it (car ,l))
(,n ,form))
(unless (equal ,v ,n)
(!cons (nreverse ,s) ,r)
(setq ,s nil)
(setq ,v ,n))
(!cons it ,s)
(!cdr ,l)))
(!cons (nreverse ,s) ,r)
(nreverse ,r))))))
#+end_example
could then be rewritten as
#+begin_example emacs-lisp
(defmacro --partition-by ( form list
&gensym result sublist value new-value list)
"Anaphoric form of `-partition-by'."
(declare (debug (form form)))
`(when ,list
(let* ((,result nil)
(it (car ,list))
(,sublist (list it))
(,value ,form)
(,list (cdr ,list)))
(while ,list
(let* ((it (car ,list))
(,new-value ,form))
(unless (equal ,value ,new-value)
(!cons (nreverse ,sublist) ,result)
(setq ,sublist nil)
(setq ,value ,new-value))
(!cons it ,sublist)
(!cdr ,list)))
(!cons (nreverse ,sublist) ,result)
(nreverse ,result))))
#+end_example
Lambda list keyword ~&gensym~, as implemented below, also provides
~once-only~ functionality. For example, the definition
#+begin_example emacs-lisp
(defmacro with-file-buffer (filename &rest body)
"Visit FILENAME unless already visited. Set the buffer as current,
evaluate BODY forms. Kill the buffer if it did not exist initially."
(declare (indent 1))
(let ((o-o-filename (gensym "filename-"))
(exists-g (gensym "exists-"))
(buffer-g (gensym "buffer-")))
`(let* ((,o-o-filename ,filename)
(,exists-g (get-file-buffer ,o-o-filename))
(,buffer-g (or ,exists-g (find-file-noselect ,o-o-filename))))
(unwind-protect (with-current-buffer ,buffer-g ,@body)
(unless ,exists-g (kill-buffer ,buffer-g))))))
#+end_example
could be rewritten as
#+begin_example emacs-lisp
(defmacro with-file-buffer ( filename &rest body
&gensym
filename
(exists (get-file-buffer filename))
(buffer (or exists
(find-file-noselect filename))))
"Visit FILENAME unless already visited. Set the buffer as current,
evaluate BODY forms. Kill the buffer if it did not exist initially."
(declare (indent 1))
`(unwind-protect (with-current-buffer ,buffer ,@body)
(unless ,exists (kill-buffer ,buffer))))
#+end_example
This ~&gensym~ facility eliminates the need for ~with-gensyms~ and
~once-only~ in cases when gensyms are created unconditionally by macro
function (in Common Lisp parlance).
An implementation ~defmacro/&gensym~ is accessible at
git@gitlab.com:akater/defmacro-gensym.git
It is a fairly lengthy (26.6k words) Org file with exposition,
motivation, somewhat extensive tests (for the macro, its variations
and essential dependencies), examples, a ~cl-demacro/&gensym~ version
that supports destructuring lambda lists, and variations which expand
constants early. There are 118 tests and examples for all the
variations in total. The file can be tangled to a self-contained
elisp file that provides the macros in question.
Patch not provided because my implementation depends significantly on
~cl-symbol-macrolet~ which doesn't look like it could be used in such
a low-level code.
signature.asc
Description: PGP signature
- defmacro with built-in gensym declaration and initialization,
akater <=
- Re: defmacro with built-in gensym declaration and initialization, Basil L. Contovounesios, 2021/01/20
- Re: defmacro with built-in gensym declaration and initialization, Stefan Monnier, 2021/01/20
- Re: defmacro with built-in gensym declaration and initialization, akater, 2021/01/20
- Re: defmacro with built-in gensym declaration and initialization, Basil L. Contovounesios, 2021/01/20
- Re: defmacro with built-in gensym declaration and initialization, akater, 2021/01/21
- Re: defmacro with built-in gensym declaration and initialization, Stefan Monnier, 2021/01/21
- Re: defmacro with built-in gensym declaration and initialization, Basil L. Contovounesios, 2021/01/21
- Re: defmacro with built-in gensym declaration and initialization, Stefan Monnier, 2021/01/21
- Re: defmacro with built-in gensym declaration and initialization, Basil L. Contovounesios, 2021/01/21