问题
Since Clojure 1.3, I am confused about the directory structure needed to build something in Clojure. I am using cake to build and cake repl.
Here is what works. I have a working build directory addr_verify. The main's and ns's name is addr-verify. The project.clj refers to addr-verify as main, and in addr_verify/src there is addr_verify.clj. The ns inside addr_verify.clj refers to the addr-verify name space.
Now, I had a directory mr1, but cake won't compile it right at line 1
(ns mr1
(use ['clojure.string :only '(split)])
(use ['clojure.string :only '(join)])
)
If mr1 is a bad name, what naming convention should I use?
I have tried mr1_app as a directory structure using mr1-app as the main name and ns name. I
For mr1 as the directory and ns name, I get
Caused by: clojure.lang.Compiler$CompilerException: java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to java.lang.Comparable, compiling:(mr1.clj:1)
I'm just not getting what I'm doing wrong here, and I know it's probably something really simple.
Edit:
Why does the binary mr1 not have a main?
mr1/project.clj
(defproject mr1 "0.0.1-SNAPSHOT"
:description "TODO: add summary of your project"
:dependencies [[org.clojure/clojure "1.3.0"]
[org.clojure/tools.cli "0.1.0"]]
:main mr1)
mr1/src/mr1.clj
(ns mr1
(:use [clojure.string :only [split]]
[clojure.string :only [join]]))
(def grid-dim (atom '(0 0)))
(def mr1-pos (atom '(0 0)))
(def mr2-pos (atom '(0 0)))
(defn cvt-str-to-int
[string]
(map #(Integer/parseInt %)
(split string #" ")))
(defn prompt-for-grid-dim
[]
(do
(println "Enter the dimensions of the grid (10 10) ")
(cvt-str-to-int (read-line))
))
(defn prompt-for-rover-pos
[rover-num]
(do
(println "Enter rover's initial position on the grid (2 4) ")
(cvt-str-to-int (read-line))
))
(defn prompt-for-rover-moves
[]
(do
(println "Enter rover's moves LMMRM ")
(read-line)
))
(defn -main
[& args]
(do
(reset! grid-dim (cvt-str-to-int (prompt-for-grid-dim)))
(reset! mr1-pos (cvt-str-to-int (prompt-for-rover-pos)))
)
)
回答1:
I think there is something wrong with the "syntax" of your namespace declaration. Instead, try this:
(ns mr1
(:use [clojure.string :only [split]]
[clojure.string :only [join]]))
Change your :main setting in project.clj accordingly: it should just be mr1
, contrary to what I said earlier.
Edited according the comment of googolplex
回答2:
Since the first part has already been answered, I will answer the part about :main
.
As sample.project.clj file says, :main
key should have as an assigned value a namespace which contains -main
function. So you should have such function
(defn -main [& args]
(do-things-you-want-to-do-on-program-start))
in your mr1.clj. Also AFAIR if you want to use your program as a standalone jar you have to have this namespace gen-classed. By this I mean that you have to:
Include
:gen-class
option in your namespace definition like this:(ns mr1 (:gen-class) ...other options...)
Make the namespace AOT-compiled (AOT stands for Ahead Of Time). To do this you need to specify your namespace in the list of AOT-compiled namespaces in project.clj:
(defproject mr1 "0.0.1-SNAPSHOT" ...other definitions... :aot [mr1] :main mr1)
After you've done this, you can use cake
to generate executable jar for you.
ADD:
I think it is worth to note that you don't have to have a :main
at all. If all you want to do is to run your program in repl or if you want to create a library, there can be no gen-classes namespaces (except if you want to interact with plain java code in such a way that java code can call your clojure code) and no :main
namespace, which are required only for executable jars.
来源:https://stackoverflow.com/questions/8465157/determining-why-clojure-repl-load-file-and-cake-build-yield-error