2010-03-07 47 views
5

我刚开始使用Clojure玩,我写了一个小脚本来帮助我了解一些功能。它是这样开始的:迷茫“让” 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导致崩溃?

回答

7

你有一组额外的周围do括号。您的代码是这样做的:

((do ...)) 

它试图执行(如函数调用)整个do形式的价值,但do正在恢复nil,因为在do形式最后println返回nil

注意,你的缩进风格是非标准的。你不应该把闭嘴的人放在他们自己的路线上。而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) 
+0

这固定它。感谢您的缩进样式提示。 – 2010-03-07 03:56:08

1

布莱恩已经回答了你的问题,所以我只是想给你的,让形式有一般指示:

4

我觉得其他的答案被忽略了房间里的大象:你为什么要这么做?有很多的代码中的东西,让我担心你是在错误的道路上锻造通过学习Clojure的:

  • 使用全局绑定(exprs到测试
  • 使用doseq /的println到尝试依次
  • 代码使用eval

最好的方式来学习的Clojure的API的是通过REPL。您应该设置您的环境,无论是Vim,Emacs还是IDE,以便您可以轻松地在文本文件中的静态代码和交互式REPL之间来回移动。 Here is a good breakdown of a number of Clojure IDEs

现在,只要你的代码去,几件事情要记住。首先,使用eval几乎没有好的理由。如果你发现自己这样做,问问自己是否真的有必要。其次,请记住,Clojure是一种功能性语言,通常您不需要使用“do”宏集。当你需要有副作用的“做”宏是有用的(在你的榜样,副作用是*出*中的println)最后,使用全局变量应尽量避免为好。如果您确实需要使用变量,则应该考虑使用绑定宏将变量本地绑定到线程以保证不可变的值,因此不存在并发问题。

我绝对建议你花时间拿起编程的Clojure或其他更深的参考LISP真正了解你对编程有效利用Clojure的方式需要转变。这里的小样本让我觉得好像你正试图在Clojure中编写不具有代码的代码,而这一切都不会很好。

+0

我知道全局只是出在这个10行的脚本控制的,我不会用“做”宏和eval了,甚至在他们实际需要的情况。我也会接受你对REPL的建议,因为我对我只用了10分钟的语言有完美的记忆,而且我不需要保存我的作品供以后参考。作为一名经验丰富的Clojure专业人士,你的正义无知让我感到羞愧。下次我会更努力。 – 2010-03-18 02:54:58

+0

多么令人作呕的讽刺和讽刺的评论。我正在试图帮助。真丢脸。 – 2010-03-18 05:58:19

+0

我不认为适合忽略这个问题,并忽略初学者的代码不完美。感觉更像是吹响自己的小号,而不是试图帮助。 – 2010-03-18 07:22:06