2

我正在尝试编写一个小型宏系统来在 Emacs Lisp 中执行迭代任务。我理所当然地认为除了while循环之外没有什么。没有更多的原语或一些隐藏的功能,但我决定,我最好问问。

我所说的“隐藏特征”是指类似于tagbodyCommon Lisp 中的东西,即根据块、跳转和标签对代码进行建模的非常原始的形式。eLisp 中有这样的东西吗?甚至没有以任何“hackish”方式,例如通过字节码?当然,我知道(catch ... (throw ... ))construct,但它并不完全相同,因为它只允许“向后”跳跃,而不能向前跳跃。我还假设它是一个相当复杂的构造,不适合构建快速迭代原语。

让我烦恼的另一件事是似乎没有办法为哈希表创建迭代器。即必须使用一个哈希表来迭代maphash,一旦你退出maphash函数,就不会回到你离开它的地方。到目前为止,我了解,它必须执行类似导出键向量和值向量并对其进行迭代的操作,但似乎没有办法获取这些向量/列表/无论它们是什么。还是我又错了?

我研究了 package 如何为and / /cl生成代码,但他们只是使用or ,无论哪个合适,而且坦率地说,我不太喜欢他们的代码......有两个子句,它们只是忽略第一个(您甚至不会收到警告)并为第二个生成代码:|loopdotimesdolistdowhilemaphashloopfor-as-hash

是否有一些技巧可以从 eLisp 中的用户代码中获取这些迭代原语?如果不是,那么用 C 语言编写扩展是多么可行,而且真的是这样吗?

4

2 回答 2

3

你可以tagbody作为一个宏:

   (defmacro cl-tagbody (&rest tags-or-stmts)
     (let ((blocks '()))
       (let ((block (list 'cl--preamble)))
         (dolist (tag-or-stmt tags-or-stmts)
           (if (consp tag-or-stmt) (push tag-or-stmt block)
             ;; Add a "go to next block" to implement the fallthrough.
             (push (nreverse (cons `(go ,tag-or-stmt) block)) blocks)
             (setq block (list tag-or-stmt))))
         (push (nreverse (cons `(go cl--exit) block)) blocks))
       (let ((catch-tag (make-symbol "cl--tagbody-tag")))
         (macroexpand-all
          `(let ((next-tag 'cl--preamble))
             (while
                 (not (eq (setq next-tag
                                (catch ',catch-tag
                                  (cl-case next-tag
                                    ,@blocks)))
                          'cl--exit))))
          `((go . (lambda (tag) `(throw ',catch-tag ',tag)))
            ,@macroexpand-all-environment)))))
于 2012-12-04T14:20:07.140 回答
2

1. 其他循环结构?

Emacs Lisp 中唯一通用的内置循环结构是while(请参阅参考资料eval.c)。宏dolistdotimes( insubr.el ) 都使用while.

还有用于映射各种数据结构的内置函数:mapatoms, mapc, mapcar, map-char-table, mapconcat, maphash, 和map-keymap. 但是这些实现方式是您不能将它们的执行与其他 Lisp 代码交错执行(例如参见 参考资料maphashfns.c。如果你想遍历两个这样的数据结构,你必须遍历一个然后遍历另一个。

所以我认为你基本上不走运。

2. 扩展?

Emacs 被刻意设计为不具有动态 C 级扩展,以使某人更难以对 Emacs 用户的自由进行“拥抱和扩展”攻击(例如,请参阅此处开始的 emacs-devel 线程)。

因此,如果要添加 C 级功能,则必须编辑源代码。祝你好运!

于 2012-12-04T16:06:26.877 回答