I'm new to Clojure, and I'm building a small function that reads tuples from a file and check if the first element is already in a (atom{})
.
But I keep receiving NullPointerException
at line ((println "OK")))
after the first iteration. What am I doing wrong? Here is the code:
(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")))
)))
)
Note that the code is simple, and the outputs (WHAT? and "OK") are here just for demonstration purposes.
Here is the output I get:
src: 64 dst: 48 kw: :64
OK
NullPointerException ****/graph-from-file (core.clj:19)
You have an extra layer of parentheses: ((println "OK"))
.
The result of (println "OK")
is a nil
, so the extra pair of parenthesis looks like a function call on nil: (nil)
. In Java the equivlant code would be null()
, which doesn't make any sense.
Remember that in Clojure, parentheses mean "function call".
UPDATE 2015-9-17:
If function syntax is:
(if <cond-expr>
<true-expr>
<false-expr> )
The 3 expressions may be either constant values like 5
or a function call like (+ 2 3)
. The return value of the entire (if ...)
expression is the result of either <true-expr>
or <false-expr>
. So we get:
(if true
:wahoo
"no such luck" ))
;=> :wahoo
and
(if (< (+ 2 3) 9)
(str "Two plus three is " (+ 2 3))
:not-likely ))
;=> Two plus three is 5
UPDATE 2015-11-1
The syntax is as follows:
(if test-value
result-value-if-true
result-value-if-false)
The first example results in :wahoo
with all three values being literals (i.e. constants). In Clojure, any value can be replaced by an expression:
(if (< 2 3)
(+ 9 10)
(- 9 10))
;=> 19
Each value in the above example has been replaced by a function call. The result of (< 2 3)
is true, so the function (+ 9 10)
is evaluated and the result of that function is returned as the result of the whole (if ...)
expression. So, we get the result 19
instead of -1
.
Remember, in Clojure parentheses mean "function call". You have to un-learn the idea from Java, et al that parentheses are often used as a "grouping operator". In Java,
2 = (2) = ((2)) = ...
since repeatedly "grouping" a value makes no difference. In Clojure, the syntax (2)
means "find the function named 2
and call it with zero arguments (in Java this would be 2()
which is illegal).