Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure: Lein run unable to resolve symbol

Tags:

clojure

I just started on my first clojure project using lein, the code here:

(ns fileops.core
  (:use
    [clojure.core :only (slurp)]
    [clojure-csv.core :only (parse-csv)]
    [fileops.core]))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (read-file "sample.csv"))

(defn read-file
  "open and read the csv file"
  [fname]
  (with-open [file (clojure.java.io/reader fname)]
    (parse-csv (slurp fname))))

I tried to run this using "lein run" but I keep getting this error:

Caused by: java.lang.RuntimeException: Unable to resolve symbol: read-file in this context
    at clojure.lang.Util.runtimeException(Util.java:219)
    at clojure.lang.Compiler.resolveIn(Compiler.java:6874)
    at clojure.lang.Compiler.resolve(Compiler.java:6818)
    at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6779)
    at clojure.lang.Compiler.analyze(Compiler.java:6343)
    ... 52 more

What am I doing wrong?

like image 319
jwesonga Avatar asked May 18 '14 00:05

jwesonga


People also ask

Why is my eventualling failing in Clojure?

Explanations: Clojure did not find any existing namespace named a.b.c, then searched the classpath for a lib that would define it, eventualling failing with the above Exception. The cause may vary:

How do I fix the ‘classnotfoundexception’ error in Clojure?

Note that the error message (‘ClassNotFoundException’) is particularly confusing in this case: the reason is that the Clojure compiler, having found no loaded namespace named clojure.set , is trying to interpret clojure.set as a Java class. The solution is to make sure the clojure.set lib has been loaded.

Why is my-non-existent-name not working in the REPL?

Maybe you forgot to define my-nonexistent-name in the REPL (using e.g def or defn ): this could happen if you wrote a (def my-nonexistent-name …​) in your code file but forgot to evaluate it in the REPL. Maybe you defined my-non-existent-name, but in another namespace.


2 Answers

You have used only slurp from clojure core, meaning that every other core function is now unavailable to you :) Try changing your ns to use :require instead of :use, as this is more idiomatic.

One thing to note is that order does matter in clojure, so if you don't declare a function at the top of your file, as in C and some other languages, the earlier functions will not be able to make reference to them. This is what was causing your error before and is why I like to define my -main function at the bottom. It's a matter of style.

Another thing is that your -main function is taking variable args right now and not using them. In Clojure it is idiomatic to use _ to refer to a parameter that doesn't get used. You could use & _ to avoid error messages, for when the user passes in unnecessary args, but I would just have the -main function parameterless from the start. This is because nothing needs to be provided to main when you run the program, and errors do make debugging easier. It is good to know what is getting used and where. The sample.csv file is already provided and is having read-file called on it, so the program should run if your read-file function is correct and the sample.csv file is in the proper location.

Regarding your -main function, it would be nice to put a little test in there to see if it executes properly when you run it, so I changed it to print out the contents of the csv file onto your console. This way of printing from a file is efficient and worth studying in its own right.

Finally, Make sure you include clojure-csv.core in your project.clj file.

core.clj:

(ns fileops.core
  (:require
    [clojure-csv.core :refer [parse-csv]]))

(defn read-file
  "open and read the csv file"
  [fname]
  (with-open [file (clojure.java.io/reader fname)]
    (parse-csv (slurp fname)))) 

 (defn -main []
        (println (clojure.string/join "\n" (read-file "resources/test.csv"))))

project.clj:

...

:dependencies [[org.clojure/clojure "1.5.1"]
               [clojure-csv/clojure-csv "2.0.1"]
                ...]
:main fileops.core

You need to declare fileops.core as :main, as shown above. This tells Leiningen what function to execute when you enter lein run. Very important and tricky stuff.

So now make sure you are in the root of your project directory and at the terminal, run the following:

lein clean
lein deps 
lein run 

Good luck!

Further reading:

8th light blog on name-spaces

flying machine studios explanation of lein run

like image 196
kurofune Avatar answered Sep 19 '22 15:09

kurofune


read-file should be before main in your source OR you should put before -main a declare cause like that:

(declare read-file)
like image 28
Damien Mattei Avatar answered Sep 19 '22 15:09

Damien Mattei