flatten-tree为何展开lambda体?求Emacs Lisp符合预期的内置函数
Emacs Lisp中flatten-tree行为差异及替代方案
为什么flatten-tree会展开lambda函数体?
Emacs Lisp里的lambda本质是一个特殊列表(执行(listp (lambda () 42))会返回t),而flatten-tree的核心逻辑是递归展开所有列表结构——它不会区分普通列表和lambda这类特殊表单,只要元素是列表类型,就会逐层拆解,直到所有元素都不再是列表为止。
你自己实现的flatten函数仅做了顶层列表的一层展开:只把直接子列表的元素平铺到顶层,不会递归处理子列表内部的结构;同时对于lambda这种列表,你直接将其作为整体保留,因此得到了保留lambda完整结构的结果。
如何实现保留特殊表单的扁平化?
Emacs没有直接内置符合该需求的函数,但可以自定义递归扁平化函数,通过判断元素是否为特殊表单来决定是否展开。示例实现如下:
(defun my-flatten (lst) (mapcan (lambda (x) (cond ;; 对lambda、defun这类特殊表单,直接作为单个元素保留 ((and (consp x) (memq (car x) '(lambda defun quote))) (list x)) ;; 普通列表则递归展开 ((consp x) (my-flatten x)) ;; 非列表元素直接返回 (t (list x)))) lst))
测试验证:
(my-flatten (list :hoge (lambda () 42))) ;; => (:hoge (lambda nil 42))
如果只需要顶层一层展开(不需要递归处理深层普通列表),修正你原有实现的语法错误后即可使用:
(defun flatten (list) (mapcan (lambda (x) (if (listp x) x (list x))) list)) (flatten (list :hoge (lambda () 42))) ;; => (:hoge (lambda nil 42))
内容的提问来源于stack exchange,提问作者yskkin
相关产品推荐
相关产品推荐

