我刚开始玩Clojure,我写了一个小脚本来帮助我理解一些功能。它是这样开始的:
(def *exprs-to-test* [
"(filter #(< % 3) '(1 2 3 4 3 2 1))"
"(remove #(< % 3) '(1 2 3 4 3 2 1))"
"(distinct '(1 2 3 4 3 2 1))"
])
然后它通过*exprs-to-test*
,对它们进行全面评估,然后输出如下输出:
(doseq [exstr *exprs-to-test*]
(do
(println "===" (first (read-string exstr)) "=========================")
(println "Code: " exstr)
(println "Eval: " (eval (read-string exstr)))
)
)
以上代码一切正常。但是,重复了(read-string exstr)
,所以我尝试使用let
来消除重复,如下所示:
(doseq [exstr *exprs-to-test*]
(let [ex (read-string exstr)] (
(do
(println "===" (first ex) "=========================")
(println "Code: " exstr)
(println "Eval: " (eval ex))
)
))
)
但这对*exprs-to-test*
中的第一项有效,然后与NullPointerException
崩溃。为什么添加let
导致崩溃?
答案 0 :(得分:7)
do
表单周围有一组额外的括号。您的代码正在执行此操作:
((do ...))
它正在尝试执行(作为函数调用)整个do
表单的值,但do
正在返回nil
,因为println
中的最后一个do
{1}}表单返回nil
。
注意,您的缩进样式是非标准的。你不应该把关闭的parens放在他们自己的线上。 let
有一个隐含的do
,所以你不需要那里有user> (doseq [exstr *exprs-to-test*]
(let [ex (read-string exstr)]
(println "===" (first ex) "=========================")
(println "Code: " exstr)
(println "Eval: " (eval ex))))
=== filter =========================
Code: (filter #(< % 3) '(1 2 3 4 3 2 1))
Eval: (1 2 2 1)
=== remove =========================
Code: (remove #(< % 3) '(1 2 3 4 3 2 1))
Eval: (3 4 3)
=== distinct =========================
Code: (distinct '(1 2 3 4 3 2 1))
Eval: (1 2 3 4)
。试试这个:
{{1}}
答案 1 :(得分:4)
我认为其他答案都忽略了房间里的大象:你为什么要这样做?你的代码中有很多东西让我担心你是通过学习Clojure来走错路:
学习Clojure API的最佳方法是通过REPL。您应该设置环境,无论是Vim,Emacs还是IDE,以便您可以轻松地在文本文件中的静态代码和交互式REPL之间来回切换。 Here is a good breakdown of a number of Clojure IDEs
现在,就你的代码而言,要记住一些事情。首先,使用eval几乎没有充分的理由。如果你发现自己这样做,问问自己是否真的有必要。其次,请记住,Clojure是一种函数式语言,通常你不需要使用“do”宏集。当你需要副作用时,“do”宏很有用(在你的例子中,副作用是println到* out *)最后,也应该避免使用全局变量。如果确实需要使用vars,则应考虑使用bindings宏将本地的vars绑定到不可变的值,这样就不存在并发问题。
我绝对建议你花时间学习编程Clojure或者对LISP的另一个更深入的参考,以真正理解你对编程的有效转变,以有效地利用Clojure。你在这里的小样本让我感觉好像你正试图在Clojure中编写不完整的代码,这根本不会很好用。
答案 2 :(得分:1)
Brian已经回答了你的问题,所以我只想给你一些关于let-form的一般指示: