Artur, do you have any thoughts on the below patch? Spencer Baugh <sba...@janestreet.com> writes:
> From 28e52a343f72dddd991cafd23fea910cc5f64ac5 Mon Sep 17 00:00:00 2001 > From: Spencer Baugh <sba...@janestreet.com> > Date: Thu, 12 Oct 2023 18:01:46 -0400 > Subject: [PATCH] Support numeric indexing in let-alist > > let-alist is very useful. But sometimes an alist contains a list in > the middle, which contains yet more alists. Previously, this was > somewhat painful to deal with, and required something like: > > (let-alist alist > (let-alist (nth 0 .a) > (let-alist (nth 3 .b) > .c))) > > Now, the following works: > > (let-alist alist > .a.0.b.3.c) > > * lisp/emacs-lisp/let-alist.el (let-alist--access-sexp): Properly > parse numbers. > (let-alist--list-to-sexp): Use nth to handle numbers. > (let-alist): Update docs. > --- > lisp/emacs-lisp/let-alist.el | 25 +++++++++++++++---------- > 1 file changed, 15 insertions(+), 10 deletions(-) > > diff --git a/lisp/emacs-lisp/let-alist.el b/lisp/emacs-lisp/let-alist.el > index d9ad46b2af7..de7c087bf2a 100644 > --- a/lisp/emacs-lisp/let-alist.el > +++ b/lisp/emacs-lisp/let-alist.el > @@ -36,22 +36,23 @@ > ;; symbol inside body is let-bound to their cdrs in the alist. Dotted > ;; symbol is any symbol starting with a `.'. Only those present in > ;; the body are let-bound and this search is done at compile time. > +;; A number will result in a list index. > ;; > ;; For instance, the following code > ;; > ;; (let-alist alist > -;; (if (and .title .body) > +;; (if (and .title.0 .body) > ;; .body > ;; .site > ;; .site.contents)) > ;; > ;; essentially expands to > ;; > -;; (let ((.title (cdr (assq 'title alist))) > +;; (let ((.title.0 (nth 0 (cdr (assq 'title alist)))) > ;; (.body (cdr (assq 'body alist))) > ;; (.site (cdr (assq 'site alist))) > ;; (.site.contents (cdr (assq 'contents (cdr (assq 'site alist)))))) > -;; (if (and .title .body) > +;; (if (and .title.0 .body) > ;; .body > ;; .site > ;; .site.contents)) > @@ -93,14 +94,17 @@ let-alist--access-sexp > (if (string-match "\\`\\." name) > clean > (let-alist--list-to-sexp > - (mapcar #'intern (nreverse (split-string name "\\."))) > + (mapcar #'read (nreverse (split-string name "\\."))) > variable)))) > > (defun let-alist--list-to-sexp (list var) > "Turn symbols LIST into recursive calls to `cdr' `assq' on VAR." > - `(cdr (assq ',(car list) > - ,(if (cdr list) (let-alist--list-to-sexp (cdr list) var) > - var)))) > + (let ((sym (car list)) > + (rest (if (cdr list) (let-alist--list-to-sexp (cdr list) var) > + var))) > + (cond > + ((numberp sym) `(nth ,sym ,rest)) > + (t `(cdr (assq ',sym ,rest)))))) > > (defun let-alist--remove-dot (symbol) > "Return SYMBOL, sans an initial dot." > @@ -116,22 +120,23 @@ let-alist > "Let-bind dotted symbols to their cdrs in ALIST and execute BODY. > Dotted symbol is any symbol starting with a `.'. Only those present > in BODY are let-bound and this search is done at compile time. > +A number will result in a list index. > > For instance, the following code > > (let-alist alist > - (if (and .title .body) > + (if (and .title.0 .body) > .body > .site > .site.contents)) > > essentially expands to > > - (let ((.title (cdr (assq \\='title alist))) > + (let ((.title (nth 0 (cdr (assq \\='title alist)))) > (.body (cdr (assq \\='body alist))) > (.site (cdr (assq \\='site alist))) > (.site.contents (cdr (assq \\='contents (cdr (assq \\='site > alist)))))) > - (if (and .title .body) > + (if (and .title.0 .body) > .body > .site > .site.contents))