2010-01-14 61 views
5

我正在和clojure一起工作,雖然我之前曾經和lisp一起討論過,但我很難找到一種乾淨的方法在cond語句中嵌套let語句。例如,考慮下面的函數:let cond

(defn operate-on-list [xs] 
    (let [[unpack vector] (first xs)] 
    (cond 
     [(empty? xs) 'empty 
     unpack vector 
     :else (operate-on-list (rest xs))]))) 

這是名單上的一個非常標準的遞歸操作,但它需要做的列表中的第一個元素上的一些工作與它的內容的作品前。這個問題當然是列表可能是空的。

在這個例子中,它不會是很難改變unpack((first xs) 0)vector((first xs) 1),但如果更多的工作需要在(第一XS)做到了這一點很快變得難看。

有沒有什麼辦法有效地使用let語句部分通過cond?

謝謝。

-Nate

+0

嗨發現 - 這是我不清楚你想在這裏實現什麼。您可能會發現這個有趣的http://www.assembla.com/spaces/clojure/tickets/200和http://groups.google.com/group/clojure/browse_thread/thread/c1097ce07506fc39請考慮說明該功能應該是什麼做你的問題,以及一些示例輸入和輸出。該語法看起來不像一個有效的cond語句,因爲cond的主體被包裝在一個向量中。 – 2010-01-15 00:16:47

回答

11

在這樣的情況下,你最好使用if-let

(defn operate-on-list [xs] 
    (if-let [[unpack v] (first xs)] 
    (cond 
     unpack v 
     :else (operate-on-list (rest xs))))) 

此代碼走給出 列表 SEQ-能( list,vector,array ...)並返回第一個向量的第一個元素爲true的第二個元素(意思是不是falsenil)。如果未找到此類矢量,則返回nil

請注意,vector是一個內置函數,所以我選擇了v作爲變量名,以防將來需要使用函數。更重要的是,你在cond語法中使用了太多的括號。在此版本中修復。

UPDATE:兩個額外的事情值得一提的約if-let

  1. 的方式if-let作品,如果(first xs)恰好是nilfalse將是相同的),解構綁定從來沒有發生,所以Clojure不會抱怨不能將nil綁定到[unpack v]

  2. 此外,if-let接受一個else子句(您可以在其中不是指if-let綁定向量綁定的變量 - 但如果你在else子句中的時候,你知道他們在哪裏falsenil反正)。

+2

另請參閱'when-let',當你只有一個分支時更具慣用意義。 – kotarak 2010-01-15 09:05:40

+0

第二個注意事項:注意'if-let'在這裏工作,因爲列表應該包含向量。一般情況下'(when-let [x(first s)] ...)'* *不代替'(when-let [s(seq s)](let [f(first s)] ... ))'。 – kotarak 2010-01-15 09:09:15

2

有點像這樣,用letcond的範圍內?

(defn operate-on-list [list] 
    (let [ el_first (first list) ] 
    (cond 
     (nil? el_first) (println "Finished") 
     :else (do 
     (let [ list_rest (rest list) ] 
       (println el_first) 
       (operate-on-list list_rest)))))) 

(operate-on-list '(1 2 3)) 

輸出是:

1 
2 
3 
Finished 
+4

你的'do'是多餘的。 – 2010-01-15 19:46:46

+0

@Brian Carper:你是對的;你可以簡單地省略do。對我而言,這是一個Elisp宿醉(特別是預後)。 – 2010-01-18 23:13:10