Clojure NullPointerException错误

Clojure NullPointerException错误,exception,clojure,nullpointerexception,Exception,Clojure,Nullpointerexception,我是clojure的新手,尝试编写一个简单的函数来获取数字列表并只过滤偶数 我想做它没有过滤器,甚至?只有纯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)) 但是得

我是clojure的新手,尝试编写一个简单的函数来获取数字列表并只过滤偶数

我想做它没有过滤器,甚至?只有纯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)>
#
怎么了

谢谢。

您的递归函数
my even
没有基本情况。当列表中没有更多元素时会发生什么
(第一个ilist)
返回
nil
(mod nil 2)
抛出NullPointerException


您必须以某种方式测试空列表。

正如乔纳斯所说,您没有基本情况;除此之外,将paren放在单独的行上不是惯用的Clojure(或任何其他Lisp),还可以将
if
的谓词保持在同一行上

通过分解结构,它的可读性更强:

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

这周看到这么多人学习Clojure真是太好了:)从这样一个基本问题开始是一个非常好的开始。哈姆扎和乔纳斯的回答显然很好地涵盖了最初的问题。我想提供一些未经请求的建议,从这里开始,希望能有所帮助

一旦有了基本递归形式,您可以通过以下方式将其转换为惯用Clojure:

1) 尽可能使用尾部递归表单(您已经这样做了)
2) 将直接递归替换为
recur
调用,以避免破坏堆栈。(从Hamza的工作答案开始)

recur
使编译器跳转到堆栈帧的开头,而不是分配新的堆栈帧。如果没有这一点,它将毁掉这堆东西

3) 在许多情况下,您可以使用高阶函数消除
(defn[…(recur))
模式,如
map
reduce
filter
for
,等等。在本练习中,我看到您试图不使用
filter
甚至
,所以很明显,你可以写我的过滤器和我的偶数,那就好了;)

4) 将可分割的部分(构建列表,选择要包含的内容)提取到可重用函数中,并上载对clojure contrib项目通常有用的任何部分:)


5) 如果您发现自己正在使用
(lazy seq…
,请仔细思考,因为您很有可能正在重新发明轮子

这里是另一个不需要解构的解决方案,只需要基本的lisp和类似scheme的函数

(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))))

对不起,我编辑了,不是那个代码。只有我的晚安你真的不应该测试
coll
,而是
(seq coll)
。大多数情况下,这并不重要,但请尝试
(我的偶数?(范围0))
。在最后两行中使用recur而不是我的偶数,否则会得到一个很好的结果stackOverFlowException@Arthur仅当列表为“长”时。的确,对于非学习练习代码,您需要使用recur来优化尾部调用,以避免消耗太多堆栈帧。
(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))))