2016-06-13 70 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