elisp 怎么同时遍历 list 的索引和值

自己试了一下 loop.el 的 loop-for-each

(loop-for-each x (list 2 3)
  (if (eq x 2) 
  (print x))
  )

但我想要 同时遍历 list 的索引和值 且支持 break , continue ,return

更像 JavaScript 的

for (const [key ,value] of list){}

第一个问题:同时遍历 list 的索引和值可以使用 cl-loop (参见 (info “(cl) Loop Facility”)

(cl-loop for i from 0
         for x in '(a b c)
         collect (cons i x))

后面几个问题:一般来说,写 Emacs Lisp 会倾向于函数式风格,用到 break continue return 的几率大大小于在 C, JS 等语言。(注意 cl-loop 本身可以求出一个值,与 for 语句不同。)

如果用到了,可以使用 cl-loop 的 return (退出循环而非函数), if/when 等语句,见 (info “(cl) Other Clauses”)

break 和 return 也可以用 non-local exitcatchthrow

continue 似乎没有比较直接的对应,不过这个问题也不是很大。重申一遍,用函数式风格写代码,对这种控制流的要求会低很多。

這种宏自已隨便写写拉

(defmacro iter-list (index-var element-var list &rest body)
  (let ((rest (gensym))
        (atag (gensym))
        (btag (gensym)))
    `(cl-flet ((break () (throw (quote ,atag) nil))
               (return (x) (throw (quote ,atag) x))
               (continue () (throw (quote ,btag) nil)))
       (catch (quote ,atag)
         (cl-do* ((,index-var 0 (1+ ,index-var))
                  (,rest ,list (cdr ,rest))
                  (,element-var (car ,rest) (car ,rest)))
             ((null ,rest))
           (catch (quote ,btag)
             ,@body))))))
(iter-list i x '(a b c)
           (if (= i 1)
               (return x)))
b

(iter-list i x '(a b c)
           (if (eq x 'b)
               (continue)
             (princ (format "is:%s\n" x))))
is:a
is:c
nil

(iter-list i x '(a b c)
           (if (= i 1)
               (princ (format "is:%s\n" x))))
is:b
nil

不介意 quote hell 的话可以再改进一下。

(defmacro iter-list (index-var element-var list &rest body)
  (let ((rest (gensym))
        (atag (gensym))
        (btag (gensym)))
    `(cl-macrolet ((break () (list 'throw '',atag nil))
                   (return (x) (list 'throw '',atag x))
                   (continue () (list 'throw '',btag nil)))
       (catch ',atag
         (cl-do* ((,index-var 0 (1+ ,index-var))
                  (,rest ,list (cdr ,rest))
                  (,element-var (car ,rest) (car ,rest)))
             ((null ,rest))
           (catch ',btag
             ,@body))))))
1 个赞

这种宏还看不明白的 :joy: