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))
但出现错误:出了
#<CompilerException java.lang.NullPointerException (NO_SOURCE_FILE:0)>
什么问题?
谢谢。
I'm new in clojure and try to write simple function which get list of numbers and filter only even numbers.
I want to do it witout filter or even?, only pure clojure
(defn my-even [ilist]
(if
(= (mod (first ilist) 2) 0)
(concat (list (first ilist)) (my-even (rest ilist)))
(my-even (rest ilist))
)
)
I try to run it:
(my-even '(1,2,3,4,5))
But get error:
#<CompilerException java.lang.NullPointerException (NO_SOURCE_FILE:0)>
What's wrong?
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
正如乔纳斯所说,你没有基本情况;你没有基本情况。除此之外,将括号放在单独的行上并不是 Clojure(或任何其他 Lisp)惯用的做法,还要将
if
的谓词保持在同一行。通过解构,它的可读性更强:
As Jonas said, you do not have a base case; in addition to that it is not idiomatic Clojure (or any other Lisp) to put parens on separate lines, also keep the
if
's predicate on the same line.With destructuring it is a bit more readable:
您的递归函数
my-even
没有基本情况。当列表中没有更多元素时会发生什么?(first ilist)
返回nil
并且(mod nil 2)
抛出 NullPointerException。您必须以某种方式测试空列表。
Your recursive function
my-even
does not have a base case. What happens when there are no more elements in the list?(first ilist)
returnsnil
and(mod nil 2)
throws a NullPointerException.You must somehow test for the empty list.
很高兴本周看到这么多人学习 Clojure :) 从像这样的基本问题开始是一个非常好的开始。哈姆扎和乔纳斯的回答显然很好地涵盖了最初的问题。我想主动提供一些关于从这里获取它的建议,希望对您有所帮助。
一旦你有了基本的递归形式,你通常可以通过以下方式将其转换为惯用的 Clojure:
1)尽可能使用尾递归形式(你已经这样做了)
2) 用
recur
调用替换直接递归,以防止堆栈溢出。 (从 Hamza 的工作答案开始)recur
导致编译器跳转到堆栈帧的开头,而不是分配一个新的堆栈帧。没有这个它会破坏堆栈。3) 在许多情况下,您可以使用
map
、reduce
等高阶函数消除(defn [] ... (recur))
模式>、filter
、for
等。在本练习中,我看到您尝试不使用filter
或even
,所以显然你可以写 my-filter 和 my-even 就可以了;)4) 将可分割的部分(构建列表,选择要包含的内容)提取到可重用的函数中,并上传对 clojure contrib 项目通常有用的任何部分:)
5) 仔细思考您是否应该使用
( lazy-seq ...)
因为你很有可能重新发明轮子。It's great to see so many people learning Clojure this week :) starting with a fundamental problem like this is a really good start. Hamza and Jonas's answers clearly cover the original question quite well. I would like to offer some unsolicited advice on where to take it from here in the hopes that it will be helpful.
Once you have the base recursive form you can turn it into idiomatic Clojure generally by:
1) use tail recursive forms when you can (you already did this)
2) replace direct recursion with the
recur
call to keep from blowing the stack. (starting with Hamza's working answer)the
recur
causes the compiler to jump to the start of the stack frame instead of allocating a new one. without this it will blow the stack.3) in many cases you can eliminate the
(defn [] ... (recur))
pattern with a higher order function likemap
,reduce
,filter
,for
, etc. In this excercise I see you are trying to not usefilter
oreven
, so obviously you could write my-filter and my-even and that would be ok ;)4) extract the divisible parts, (building a list, choosing what to include) into reusable functions and upload any that are generally useful to a clojure contrib project :)
5) think very carefully should you find yourself using
(lazy-seq ...)
as there is a good chance you are re-inventing the wheel.这是另一个不需要解构的解决方案,只需要基本的 lisp 和类似方案的函数。
Here is another solution that does not require destructuring, only basic lisp and scheme-like functions.