2016-06-13 51 views
1

如何避免双递归调用(f(car l))而不使用set/setq/setf?Lisp:防止递归函数的双重调用

(defun f(l) 
    (cond 
     ((null l) nil) 
     ((listp (car l)) (append (f (car l)) (f (cdr l)) (car (f (car l))))) 
     (T (list (car l))) 
    ) 
) 

您认为以下解决办法?

(defun f(l) 
    (cond 
    ((null l) nil) 
    ((listp (car l)) 
     (funcall #'(lambda(ff) (append ff (f (cdr l)) (list (car ff)))) (f (car l)))) 
    (T (list (car l))) 
    ) 
) 
+0

这是不直接关系到你的问题,但我不明白这是什么功能是应该做的。你能解释一下吗? – coredump

+0

您必须检查它。这是一个练习......这就是它给出的全部内容。 您必须找出并保持其功能,但不要使用set/setq/setf来避免对(f(car l))进行第二次递归调用。 – esbej

+0

我重构了代码(http://pastebin.com/raw/N0Aj8Qsq),我期望append在正确的列表上运行,这就是我添加断言的原因。该函数在退化情况下适用于NIL。但是你永远不会建立一个'(foo head)',因为它的第一个元素是一个非空列表,因为递归的基本情况是'(list head)','head'是一个非列表。使用'(list(list head))'替换最后一个子句的主体可以确保函数在给定正确的列表作为输入时返回一些东西。我承认这对于这个练习可能不重要。 – coredump

回答

4

您的尝试是好的,但通常被写成:

... 
(bar (foo abcde)) 
... 
(baz (foo abcde)) 
... 

- >

(let ((r (foo abcde))) 
    ... 
    (bar r) 
    ... 
    (baz r) 
    ...) 

还指出:

(funcall #'(lambda (foo) ...) bar) 

可以Common Lisp中写入如:

((lambda (foo) ...) bar) 

或首选,前面已经提到,作为:

(let ((foo bar)) 
    ...) 
+0

感谢您的理解!我没有CLisp的任何习惯,所以谢谢你让代码干净! – esbej