我编写了一个函数,旨在映射到嵌套的正确列表的任意树,有点类似于常见的lisp函数map-into
:
(defun map-into-tree (fn tree)
"Destructive mapping into a proper tree."
(cond ((null tree) nil)
((atom (car tree))
(setf (car tree) (funcall fn (car tree)))
(map-into-tree fn (cdr tree)))
(t (map-into-tree fn (car tree))
(map-into-tree fn (cdr tree)))))
(defparameter *tree* '(1 (2) ((3)) (4 5) (6 ((7)))))
*TREE*
(map-into-tree #'1+ *tree*)
NIL
*tree*
(2 (3) ((4)) (5 6) (7 ((8))))
但是,我不确定如何对任意嵌套序列进行概括(如序列的map-into
)。任何帮助表示赞赏。
答案 0 :(得分:0)
这是一个可能的解决方案:
(defun map-into-nested-list (fn nested-list)
"Destructive mapping into a nested-list."
(cond ((null nested-list) nil)
((atom (car nested-list))
(when (car nested-list) (setf (car nested-list) (funcall fn (car nested-list))))
(map-into-nested-list fn (cdr nested-list)))
((atom (cdr nested-list))
(when (cdr nested-list) (setf (cdr nested-list) (funcall fn (cdr nested-list))))
(map-into-nested-list fn (car nested-list)))
(t (map-into-nested-list fn (car nested-list))
(map-into-nested-list fn (cdr nested-list)))))
(defvar *a* (copy-tree '((9 10) (8 9 10 11 (12 13) () (11) () 13))))
;; => *A*
(map-into-nested-list #'1+ *a*)
;; => NIL
*a*
;; => ((10 11) (9 10 11 12 (13 14) NIL (12) NIL 14))
该函数类似于map-into-tree
:主要区别在于cdr
是原子的情况下条件中存在一个新的对称分支,并且测试“原子”情况仅在原子与fn
不同时才应用函数NIL
。
答案 1 :(得分:0)
你可以致电map-into
; - )
(defun map-into-tree (function tree)
(labels
((recurse (tree)
(typecase tree
(sequence (map-into tree #'recurse tree))
(t (funcall function tree)))))
(recurse tree)))
......或等效地:
(defun map-into-tree (function tree)
(typecase tree
(sequence (map-into tree (lambda (u) (map-into-tree function u)) tree))
(t (funcall function tree))))
测试:
(map-into-tree #'1+ (copy-tree '((9 10) (8 9 10 11 (12 13) () (11) () 13))))
=> ((10 11) (9 10 11 12 (13 14) NIL (12) NIL 14))
我不确定包含字符串的树会发生什么:我们真的想迭代每个字符吗?事实上,这就是上面所做的。
我还注意到map-into与包含cons单元格的序列一起工作,但相应的map-to-tree不会,即使它使用map-into。
(1 (2 . 3))
是一个包含两个元素的正确列表,即1
和(2 . 3)
。由于map-into
没有递归到元素中,所以它只是在这两个元素上调用函数。在您的评论中,这是print
,可以毫无问题地打印不正确的列表。
第二个元素是一个序列:当你调用map-into-tree
时,函数以这个序列递归调用map-into
,这恰好是一个不正确的列表。 map-into
期望正确的序列,因此使用不正确的列表会失败。
请注意,在你的问题中,你说:
一个旨在映射到嵌套正确列表的任意树
的函数
包含不正确列表的树不是有效输入。
最后,我注意到你在文字数据上调用了破坏性函数,如下所示:
(map-into #'print '(1 2))
引用列表是常量,在运行时修改它是未定义的行为。这就是我在我的例子中首次使用copy-tree
的原因。
这样可以处理所有特殊情况[...]
由于已经存在一个类型规划,因此处理cons
的特殊情况就足够了;无论cdr
插槽中保存的值类型如何,它都能正常工作:
(defun map-into-tree (function tree)
(labels
((walk (tree)
(typecase tree
(cons
(prog1 tree
(setf (car tree) (walk (car tree)))
(setf (cdr tree) (walk (cdr tree)))))
(sequence (map-into tree #'walk tree))
(t (funcall function tree)))))
(walk tree)))