Is this an expected behaviour, or it's a problem with my Clojure installations (I'm checking it on Windows and Linux)?
I have a simple project, created with lein new app testfor. Here's the code of src/testfor/core.clj:
(ns testfor.core
(:gen-class))
(defn -main [& args]
(println "hello")
(for [x [1 2 3]]
(println x)))
When I run lein repl and invoke (-main) from the REPL, the output is this:
testfor.core=> (-main)
hello
1
2
3
But then I run the application with lein run, or lein uberjar and run the generated JAR file, the output is this:
$ lein run
hello
So, it somehow doesn't run the for loop.
Am I doing something wrong here?
I believe this is because for returns a lazy-sequence of elements - https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/for
In the example when you call the -main function from the repl, in this case the last expression in the function is returned from the function call (just like any other function call). The REPL sees the lazy-seq and attempts to print it, which requires realising the seq, which will evaluate the println statements.
In the example when you Leiningen calls the main method, it is like calling a main method on a Java class which has a void return type public static void main. Clojure will see it as lazy and nothing tries to realise the seq so the println expressions are never evaluated.
for is not a for loop like in Java. It creates a lazy sequence that depends on the different options you specify. See for documentation.
The important point in your case is the lazy word.
The repl will actually force the realisation of the lazy sequence, but when running with lein, this is not the case. In order to do what you want you need to force with either dorun or doall :
(defn -main [& args]
(println "hello")
(dorun (for [x [1 2 3]]
(println x))))
cuvier:tgo$ lein run
hello
1
2
3
Related
I'm currently in the start of making a tool that should modify all the functions in another namespace, and the run the "main" function in that (other) namespace. Almost like mocking in unit-testing, but for another purpose. The first step to this is to redefine functions from another namespace. The first listing shows code that works, where I explicitly name the function to be replaced.
(ns one)
(defn a-fun []
(println "original"))
(defn caller []
(a-fun))
(ns two)
(with-redefs [one/a-fun #(println "replaced")]
(one/caller))
;; replaced
;; nil
The next step is getting the functions programmatically from the other namespace. This is where I have run into a wall. I've experimented much with ns-publics, but so far no luck. So I try to break the problem down. And the problem is that the replacement of the function is not working. The output should print "replaced" not "original".
(ns two)
(def target (ns-resolve 'one (symbol "a-fun")))
(def caller (ns-resolve 'one (symbol "caller")))
(with-redefs [target #(println "replaced")]
(caller))
;; original
;; nil
Now, the #'two/target shows #'one/a-fun when I evaluate it in the repl. I can call one/a-fun by entering ((ns-resolve 'one (symbol "a-fun"))) in the repl, so I don't understand what part is not working.
I've been through a lot of documentation today, and I'm not really getting any closer.
You could try using with-redefs-fn like so:
(defn p [] "old")
(with-redefs-fn
{(ns-resolve *ns* 'p) #(println "new")}
(fn []
(p)))
;; => new
This does mean that the body of with-redefs-fn must be a function that uses your redefined Vars.
I've done some coding in clojure inside core.clj which have a -main method that can take 0 or more arguments:
(defn -main
"dequeue function"
[& args]
I'm loading this clj file with:
(load-file "src/exercise/core.clj")
And then i'm trying to learn how to call this within repl in order to develop core_test.clj (if there is any tips about how to develop this auto tests, please give me some hints as well). What I'm trying to do now is:
(-main "resources\\sample-input.json" "a")
But this is printing "Arguments 0" which is a message that I told the code to print just to see how many arguments are being passed with
(println "Arguments" (count *command-line-args*))
How am I suposed to do this?
Thanks!
i'm trying to learn how to call this within repl in order to develop core_test.clj
Usually you'd write other functions that are called from -main and test those rather than the app's entry point -main.
But you should be able to call -main like any other function. I have a src/sandbox/main.clj file:
(ns sandbox.main)
(defn -main [& args]
(prn args))
Starting a REPL in the project folder, I can call -main like this:
(use 'sandbox.main) ;; (load-file "src/sandbox/main.clj") also works
=> nil
(in-ns 'sandbox.main)
=> #object[clojure.lang.Namespace 0x67ccce04 "sandbox.main"]
(-main "some" "args")
;; ("some" "args")
=> nil
There's a key difference in my example though: it's printing -main's args binding; *command-line-args* is nil because you're not running the code from the command line with args, you're running it from a REPL.
Regardless, it's probably a better idea to use an existing library to work with CLI args rather than *command-line-args* directly.
I have created a Leiningen project for Exercise 2 from here. My code looks like this:
(ns random-quotes.core
(:require [clojure.string :as str])
(:gen-class))
(defn word-count [s]
(frequencies (str/split (first (str/split s #"\n")) #"\s")))
(def quote-url "http://www.braveclojure.com/random-quote")
(def total-word-count (atom {}))
(defn update-word-count []
(future
(swap! total-word-count
(partial merge-with +)
(word-count (slurp quote-url)))))
(defn quote-word-count [n]
(doseq [quote-future (doall (repeatedly n update-word-count))]
#quote-future)
#total-word-count)
(defn -main [n]
(doseq [entry (sort-by val (quote-word-count (bigdec n)))]
(println entry)))
All pretty straightforward. When I run, e.g., (-main 5) in lein repl, it runs, prints, and returns as expected. However, when I try lein run 5 instead, it runs and prints but never exits, so I am forced to use Ctrl+C to get my terminal back.
Any idea why this happens?
Clojure has a thread pool that it keeps running for use by the agents. Because those threads are still alive, the JVM can't tell that you're program is done. It's just sitting there waiting for the agents to exit. You can make them finish by calling (shutdown-agents) at the end of your program as described here. Futures use agents.
clojure.core/future-call calls an agent like this:
(let [f (binding-conveyor-fn f)
fut (.submit clojure.lang.Agent/soloExecutor ^Callable f)]
which actually starts your code running. You would not be the only one to voice some criticism of this, and we all hope a more elegant solution is found.
I would like to format my logs differently depending on whether my code is being run from a REPL or if I'm running the compiled jar.
Is there any simple way to do this? I was thinking maybe Leiningen leaves a trace somewhere when running the REPL.
(defn current-stack-trace []
(.getStackTrace (Thread/currentThread)))
(defn is-repl-stack-element [stack-element]
(and (= "clojure.main$repl" (.getClassName stack-element))
(= "doInvoke" (.getMethodName stack-element))))
(defn is-in-repl []
(some is-repl-stack-element (current-stack-trace)))
(defn my-log [msg]
(if (is-in-repl)
(prn (str "RUNNING IN REPL : " msg))
(prn msg)))
I have a basic Clojure script containing:
(def test
(future
(loop []
(println "Running")
(recur))))
However, if I execure the file with:
java -cp clojure-1.3.0.jar clojure.main test.clj
Then the screen fills with "Running". How can I change it so the future runs when I want it?
Note: I realise this will run forever, it's just an example of my problem.
A future that doesn't run immediately is just a function with no arguments.
So:
(defn test []
(println "Running")
(recur))
...Later...
(future (test))