2011-09-28 58 views
2

我是clojure的新手,並嘗試編寫一個簡單的函數,它獲取數字列表並僅過濾偶數。Clojure NullPointerException錯誤

我想這樣做,不用其他過濾器,甚至?只有純粹的Clojure

(defn my-even [ilist] 
    (if 
    (= (mod (first ilist) 2) 0) 
    (concat (list (first ilist)) (my-even (rest ilist))) 
    (my-even (rest ilist)) 
    ) 
) 

我嘗試運行它:

(my-even '(1,2,3,4,5)) 

,但得到的錯誤:

#<CompilerException java.lang.NullPointerException (NO_SOURCE_FILE:0)> 

什麼錯誤?

謝謝。

+0

這是奇怪的還是奇怪的? –

+0

對不起,我編輯過,不是那個代碼。只有我 - 甚至 – 0xAX

回答

7

正如喬納斯所說,你沒有一個基礎案例;除此之外,它不是慣用的Clojure(或任何其他Lisp)將parens放在不同的行上,還要將if的謂詞保持在同一行。

隨着解構它更是一個位可:

(defn my-even? [coll] 
    (if-let [[first & rest] coll] 
    (if (= (mod first 2) 0) 
     (cons first (my-even? rest)) 
     (my-even? rest)))) 
+0

你真的不應該測試'coll',而是'(seq coll)'。大多數情況下,這並不重要,但試試'(我 - 偶(範圍0))'。 – amalloy

+0

s/my-even/recur –

7

您的遞歸函數my-even沒有基函數。當列表中沒有更多元素時會發生什麼? (first ilist)返回nil(mod nil 2)將引發NullPointerException。

您必須以某種方式測試空列表。

3

我們很高興地看到這麼多人在本週學習Clojure的:)有一個基本的問題開始像這是一個非常好的開始。哈姆扎和喬納斯的回答很好地涵蓋了原來的問題。我想提供一些主動的建議,告訴我們從哪裏拿到它,希望它會有所幫助。

一旦你有了基本的遞歸形式,你可以通過把它變成習慣Clojure的一般:

1)使用尾遞歸形式時,你可以(你已經這樣做)
2)與recur代替直接遞歸打電話以防止吹出煙花。 (與哈姆扎的工作答案開始)

(defn my-even? [coll] 
    (if-let [[first & rest] coll] 
    (if (= (mod first 2) 0) 
     (cons first (my-even? rest)) 
     (recur rest)))) 

recur使編譯器跳轉到堆棧幀的開始,而不是分配一個新的。如果沒有這個,它會打擊堆棧。

3)在很多情況下,您可以消除(defn [] ... (recur))圖案像mapreducefilterfor等高階功能在本練習中,我看你是想不使用filtereven,所以很明顯,你可以寫我的過濾器和我,甚至和那將是確定的;)

4)提取分割部位,(建立一個列表,選擇要包含的內容)並將其添加到可重複使用的函數中,並上傳對clojure contrib項目通常有用的任何內容:)

5)仔細想一想,如果您發現自己使用(lazy-seq ...),因爲您很有可能正在重新制作輪子。

1

這是另一種解決方案,不需要解構,只需要基本的lisp和類似方案的函數。

(defn my-even [ilist]                                                      
    (cond (empty? ilist) '() ;; base case                                                    
     (= (mod (first ilist) 2) 0)                                                   
     (cons (first ilist) (my-even (next ilist)))                                               
     :else (my-even (next ilist)))) 
+1

使用recur而不是我的 - 即使是在最後兩行上,或者它會得到一個不錯的stackOverFlowException –

+0

@Arthur只有當列表是「long」時。確實,對於非學習練習代碼​​,您需要使用recur來優化尾部調用,以避免消耗太多堆棧幀。 –