1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-02-22 16:01:04 -08:00

* lisp/emacs-lisp/subr-x.el (named-let): New macro

This commit is contained in:
Stefan Monnier 2021-01-20 14:12:50 -05:00
parent 66439d31ad
commit 0d3635536d
2 changed files with 29 additions and 5 deletions

View file

@ -1554,6 +1554,13 @@ buttons in it.
This function takes a string and returns a string propertized in a way
that makes it a valid button.
** subr-x
+++
*** A number of new string manipulation functions have been added.
'string-clean-whitespace', 'string-fill', 'string-limit',
'string-lines', 'string-pad' and 'string-chop-newline'.
*** New macro `named-let` that provides Scheme's "named let" looping construct
** Miscellaneous
@ -1593,11 +1600,6 @@ length to a number).
*** New user option 'authinfo-hide-elements'.
This can be set to nil to inhibit hiding passwords in ".authinfo" files.
+++
*** A number of new string manipulation functions have been added.
'string-clean-whitespace', 'string-fill', 'string-limit',
'string-lines', 'string-pad' and 'string-chop-newline'.
+++
*** New variable 'current-minibuffer-command'.
This is like 'this-command', but it is bound recursively when entering

View file

@ -389,6 +389,28 @@ it makes no sense to convert it to a string using
(set-buffer source-buffer)
(replace-buffer-contents tmp-buffer max-secs max-costs)))))))))
(defmacro named-let (name bindings &rest body)
"Looping construct taken from Scheme.
Like `let', bind variables in BINDINGS and then evaluate BODY,
but with the twist that BODY can evaluate itself recursively by
calling NAME, where the arguments passed to NAME are used
as the new values of the bound variables in the recursive invocation."
(declare (indent 2) (debug (symbolp (&rest (symbolp form)) body)))
(require 'cl-lib)
(let ((fargs (mapcar (lambda (b) (if (consp b) (car b) b)) bindings))
(aargs (mapcar (lambda (b) (if (consp b) (cadr b))) bindings)))
;; According to the Scheme semantics of named let, `name' is not in scope
;; while evaluating the expressions in `bindings', and for this reason, the
;; "initial" function call below needs to be outside of the `cl-labels'.
;; When the "self-tco" eliminates all recursive calls, the `cl-labels'
;; expands to a lambda which the byte-compiler then combines with the
;; funcall to make a `let' so we end up with a plain `while' loop and no
;; remaining `lambda' at all.
`(funcall
(cl-labels ((,name ,fargs . ,body)) #',name)
. ,aargs)))
(provide 'subr-x)
;;; subr-x.el ends here