2011-09-28 56 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来优化尾部调用,以避免消耗太多堆栈帧。 –