我刚开始学习Lisp。我的问题是我每次在列表中发生时都试图替换一个项目。我必须使用递归并且没有任何循环来执行此操作。该函数以(subste x y L)
开头。
例子如下:
(subste 7 t '(it is 7)) → (IT IS T)
(subste 7 nil '(7 is not to (7))) → (NIL IS not TO (NIL))
(subste 7 nil '(5 is not (22))) → (5 is not (22))
以下是我的目标:
(defun subste (x y L)
(cond ((null L) nil)
((not (= (car L) x))
subste (x y (cdr L)))
((= (car L) x)
(let L 'y))))
我已多次运行并多次调整它,但考虑到错误消息提供的信息很少而且只是开始学习Lisp这一事实没有运气。感谢。
答案 0 :(得分:3)
SUBST
已经实现了您想要的行为。你似乎只想要旧元素和新元素的顺序不同,所以一个简单的包装器就可以了:
(defun subste (x y l)
(subst y x l))
如果您想为自己实现它,下面是一个简单的版本。请注意不同的分支:
nil
。这里的例子是:
(defun subste (x y l)
(cond ((null l) nil)
((eql l x) y)
((atom l) l)
(T (cons (subste x y (first l))
(subste x y (rest l))))))
此版本不完整:您无法替换非eql(如字符串或子列表)的元素。如果需要,可以将测试函数添加为参数,而不是始终使用EQL
。
答案 1 :(得分:0)
编写 subst 的实现只需要走树,检查树中的节点是否与旧相同,并用替换它们新即可。在Common Lisp中,像这样的函数通常采用测试函数来确定元素的比较方式(通常是键函数,但我在这里省略了)。这导致了这样的事情:
(defun my-subst (old new tree &key (test 'eql))
"Returns a completely fresh tree like TREE, but with occurrences of
OLD replaced by NEW. The resulting tree shares no structure with the
original TREE, except for leaves."
(cond
;; If the current tree is the OLD element,
;; return the NEW element instead.
((funcall test old tree) new)
;; If the current tree is a cons cell,
;; call MY-SUBST recursively on both
;; the CAR and CDR of the tree, and
;; then CONS the results back together.
((consp tree) (cons (my-subst old new (car tree) :test test)
(my-subst old new (cdr tree) :test test)))
;; Otherwise, just return TREE.
(t tree)))
(my-subst 'x 42 '(1 x 2 (3 x (4 (x) 5))))
;=> (1 42 2 (3 42 (4 (42) 5)))
现在,该实现返回的树总是全新的。也就是说,即使旧元素永远不会出现在树中,您仍然会得到一棵完全新鲜的树。根据您的使用情况,这可能是一种浪费,记忆。 检查递归调用的结果是否与其输入相同可能是有益的。在这种情况下,您只需返回输入:
(defun my-subst (old new tree &key (test 'eql))
"Returns a tree like TREE, but with occurrences of OLD
replaced by NEW. The resulting tree may share structure
with TREE."
(cond
((funcall test old tree) new)
((consp tree)
(let ((new-car (my-subst old new (car tree) :test test))
(new-cdr (my-subst old new (cdr tree) :test test)))
(if (and (eq (car tree) new-car)
(eq (cdr tree) new-cdr))
tree
(cons new-car new-cdr))))
(t tree)))
(let* ((t1 '(1 x 2 (3 x (4 (x) 5))))
(t2 (my-subst 'x 42 t1))
(t3 (my-subst 'y 84 t1)))
(list (eq t1 t2)
(eq t1 t3)))
;=> (NIL T) ; t1 != t2, but t1 == t3
你想要的将取决于具体情况,但能够做到这两点都很好。