2014-03-12 60 views
1

我想寫一個函數,它添加了像這樣的括號:(parens'(a b c d e))returns(a(b(c(d(e)))))。我只是沒有看到這種模式。到目前爲止,我只是在每個元素周圍返回一個帶括號的列表。我似乎無法弄清楚如何使它看起來像那樣。Lisp函數,它以某種方式添加括號

(DEFUN PARENS (L) 
    (COND ((NULL L) NIL) 
    (T (CONS (LIST (CAR L)) (PARENS (CDR L)))))) 

回答

3

列表中沒有括號。你從五個元素列表開始,(a b c d e),並獲取兩個元素列表(a (b (c (d (e)))))。第一個元素是a,第二個元素是另一個列表(b (c (d (e))))

它非常容易使用reduce得到接近這樣:

CL-USER> (reduce 'list '(a b c d e) :from-end t) 
(A (B (C (D E)))) 

你能想到的reduce爲「注入」功能list(a b c d e)生產

(list a (list b (list c (list d e)))) 

這幾乎什麼你要。你真的想要:

(list a (list b (list c (list d (list e))))) 

你會如何生產?您可以遞減列表,並且對於每個子列表​​要返回(list x (recurse ys)),但是ys()時例外。你不想遞歸到(),因爲你不想要一個包含兩個元素的列表,你實際上什麼都不需要。所以訣竅是停止遞歸比您通常使用列表更早。因此:

(defun parens (l) 
    (cond 
    ((endp l) '()) 
    ((endp (rest l)) l) 
    ((list (first l) (parens (rest l))))))  ; * 
CL-USER> (parens '(a b c d e)) 
(A (B (C (D (E))))) 
CL-USER> (parens '(a b)) 
(A (B)) 
CL-USER> (parens '(a)) 
(A) 
CL-USER> (parens '()) 
NIL 

*省略最後一句話,在t測試是故意的。如果在cond子句中沒有形式表單,則返回測試的值。因此(list …)既作爲測試形式也作爲價值形式。

我們實際上可以清理一點點。 ((endp l) '())的情況可能是((endp l) l),因爲l是空列表。但這意味着在第一和第二種情況下,我們都可以返回l。我們可以在Common Lisp中調用(rest '())並取回(),所以(rest l)()l是像(e)l()。這意味着我們可以使用:

(defun parens (l) 
    (cond 
    ((endp (rest l)) l) 
    ((list (first l) (parens (rest l)))))) 

如果我們只是有一個測試,雖然,我們還不如干脆用if

(defun parens (l) 
    (if (endp (rest l)) 
     l 
     (list (first l) (parens (rest l))))) 
0

實際上,你可以用reduce和一些特殊的考慮做結束:

(defun unflatten (list) 
    (reduce #'list list 
      :from-end t 
      :end (1- (length list)) 
      :initial-value (last list))) 

注意last返回最後ñ(默認爲1)ELEM名單經濟需求。