在Clojure中被“let”困惑

时间:2010-03-07 03:39:51

标签: clojure eval let

我刚开始玩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导致崩溃?

3 个答案:

答案 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来走错路:

  • 使用全局绑定( exprs-to-test
  • 使用doseq / println按顺序试用代码
  • 使用eval

学习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的一般指示: