在原子上迭代文件时出现 NullPointerException

NullPointerException on iterating over a file on atom

我是 Clojure 的新手,我正在构建一个从文件中读取元组并检查第一个元素是否已经在 (atom{}).

中的小函数

但在第一次迭代后,我在第 ((println "OK"))) 行继续收到 NullPointerException。我究竟做错了什么?这是代码:

(defn graph-from-file
  "Expects a string with the path for a file with a list of edges, one in each line,
And builds a graph data structure from these"
  [filepath]
  (def gr (atom{}))
  (with-open [rdr (reader filepath)]
    (doseq [line (line-seq rdr)]
      (let [[src dst] (str/split line #" ")
            ks (keyword src)]           ;define ks as the keyword
        (println (str "src: " src " dst: " dst " kw: " ks))
        (if (contains? @gr ks)
          ((println "WHAT?"))
          ((println "OK")))
        )))
  )

请注意,代码很简单,这里的输出(WHAT?和 "OK")仅用于演示目的。

这是我得到的输出:

src: 64 dst: 48 kw: :64
OK
NullPointerException   ****/graph-from-file (core.clj:19)

你多了一层括号:((println "OK")).

(println "OK") 的结果是 nil,因此额外的一对括号看起来像是对 nil 的函数调用:(nil)。在 Java 中,等效代码将是 null(),这没有任何意义。

请记住,在 Clojure 中,括号表示 "function call"。


2015-9-17 更新:

如果函数语法是:

(if <cond-expr>
  <true-expr>
  <false-expr> )

这 3 个表达式可以是像 5 这样的常量值,也可以是像 (+ 2 3) 这样的函数调用。整个 (if ...) 表达式的 return 值是 <true-expr><false-expr> 的结果。所以我们得到:

(if true
  :wahoo
  "no such luck" ))
;=> :wahoo

(if (< (+ 2 3) 9)
  (str "Two plus three is " (+ 2 3))
  :not-likely ))
;=> Two plus three is 5

更新 2015-11-1

语法如下:

(if test-value
  result-value-if-true
  result-value-if-false)

第一个示例导致 :wahoo,所有三个值都是文字(即常量)。在 Clojure 中,任何值都可以用表达式替换:

(if (< 2 3)
  (+ 9 10)
  (- 9 10))
;=> 19

上例中的每个值都已被函数调用替换。 (< 2 3) 的结果为真,因此函数 (+ 9 10) 被求值并且该函数的结果被 return 编辑为整个 (if ...) 表达式的结果。所以,我们得到结果 19 而不是 -1.

请记住,在 Clojure 中括号表示 "function call"。你必须从 Java 等人那里学习括号经常被用作 "grouping operator" 的想法。在 Java、

2 = (2) = ((2)) = ...

因为重复 "grouping" 一个值没有区别。在 Clojure 中,语法 (2) 表示“找到名为 2 的函数并使用零参数调用它(在 Java 中这将是 2(),这是非法的)。

不要将 println 调用括在两组括号中。仅使用一对。括号中的内容通常被理解为函数或宏调用。 Clojure 计算内部括号中的 println 。然后 println returns nil,由于外括号,Clojure 尝试将其用作函数。 nil 是 Java 的 null,这导致了异常。