I'm trying to understand the -main and its namespace settings. The default namespace in a -main function seems to be "user", but function defined "above" the main function, in the same file, can be called. Are they referred? I was running this to find out:
(ns ack.doodle)
(defn fo [] "bar")
(defn -main [& args]
(println (fo)) ;; bar
(println *ns*) ;; #<Namespace user>
(println (get (ns-refers *ns*) 'sorted-map)) ;; #'clojure.core/sorted-map
(println (get (ns-refers *ns*) 'fo)) ;; nil
(println (get (ns-map *ns*) 'fo)) ;; nil
(println (get (ns-publics *ns*) 'fo)) ;; nil
(println (get (ns-interns *ns*) 'fo)) ;; nil
(println (get (ns-aliases *ns*) 'fo)) ;; nil
(println (ns-resolve *ns* 'fo))) ;; nil
The call (fo) succeeds, yet apparently the symbol 'fo is not known in the current namespace *ns*. What's going on?
This problem hit me when trying to pass the name of some function, along with some arguments, as command line arguments to -main.
steps to reproduce
paste above code in a file ./src/ack/doodle.clj
create ./project.clj with these contents:
(defproject ack "1" :main ack.doodle)
run it:
lein run
It looks like leiningen runs (-main) by calling it from user namespace like that: (ack.doodle/-main). Thus *ns* is bound to the user namespace.
Try running lein repl in your project root. Then run (-main) and see what happens. :)
Didn't I answer this for you last night in #clojure? If there's something unsatisfying about the answer, you'll have to clarify your question.
Related
When I start a repl with lein repl I can run the function greet and it works as expected.
(ns var-test.core
(:gen-class))
(declare ^:dynamic x)
(defn greet []
(binding [x "Hello World."]
(println (load-string "x"))))
(defn -main [& args]
(greet))
But if run the code via lein run it fails with
java.lang.RuntimeException: Unable to resolve symbol: x in this context.
What am I missing?
Is the var x dropped during compilation, despite being declared, since it is never used outside of the string?
Edit:
Solution
#amalloy's comment helped me understand I need to bind *ns* in order load the string within the expected namespace, instead of a new, empty namespace.
This works as expected:
(ns var-test.core
(:gen-class))
(declare ^:dynamic x)
(defn greet []
(binding [x "Hello World."
*ns* (find-ns 'var-test.core)]
(println (load-string "x"))))
(defn -main [& args]
(greet))
Wow, I've never seen that function before!
According to the docs, load-string is meant to read & load forms one-at-a-time from an input string. Observe this code, made from my favorite template project:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require [tupelo.string :as str]))
(dotest
(def y "wilma")
(throws? (eval (quote y)))
(throws? (load-string "y"))
So it appears that load-string starts with a new, empty environment, then reads and evaluates forms one at a time in that new env. Since your x is not in that new environment, it can't be found and you get an error.
Try it another way:
(load-string
(str/quotes->double
"(def ^:dynamic x)
(binding [x 'fred']
(println :bb (load-string 'x'))) " ))
;=> :bb fred
In this case, we give all the code as text to load-string. It reads and eval's first the def, then the binding & nested load-string forms. Everything works as expected since the working environment contains the Var for x.
Some more code illustrates this:
(spy :cc
(load-string
"(def x 5)
x "))
with result
:cc => 5
So the eval produces the var x with value 5, then the reference to x causes the value 5 to be produced.
To my surprise, the partial load-string works in a fresh REPL:
demo.core=> (def x "fred")
#'demo.core/x
demo.core=> (load-string "x")
"fred"
So load-string must be coded to use any pre-existing
REPL environment as the base environment. When using lein run, there is no REPL environment available, so load-string starts with an empty environment.
I am a newbie to Clojure and currently trying to invoke a simple macro using defmacro and macroexpand.
(ns tutorial.core
(:gen-class)) ; namespace
(defn -main [& args]
(defmacro Simple [] (println "Hello"))
(macroexpand '(Simple))
)
Is there something I have missed? it seems the program runs without any problems but the results are not coming out as expected.
I expect the results to print out as Hello, but no outputs result from this script.
Preface:
Please see this past question for an overview of the best way to write a macro (IMHO).
Answer:
You shouldn't define the macro in the main function. Try this:
(ns demo.core)
(defmacro happy
[]
`(println "I'm happy!")) ; *** notice the backtick! ***
(defn -main [& args]
(println :expanded (macroexpand '(happy)))
(happy)
)
start up a repl:
~/expr/demo > lein repl
demo.core=> (macroexpand '(happy))
;=> (clojure.core/println "I'm happy!")
and we see that it works. Try running from the command line:
~/expr/demo > lein run
:expanded (happy) ; <= ***** OOOPS! *****
I'm happy!
Try changing the single-quote into a syntax-quote (aka backtick), then run:
(defn -main [& args]
(println :expanded (macroexpand `(happy)))
(happy))
~/expr/demo > lein run
:expanded (clojure.core/println I'm happy!)
I'm happy!
The explanation is that the syntax-quote will fully-qualify the Var happy => demo.core/happy (you can see the same effect on the println Var inside of the happy macro itself because of that syntax-quote). This allows the macroexpand to work properly. Compare with a single-quote:
(defn -main [& args]
(println :expanded (macroexpand '(demo.core/happy)))
(happy))
~/expr/demo > lein run
:expanded (clojure.core/println I'm happy!)
I'm happy!
The cause of this behavior is that, in the REPL, we see from the prompt that we are in the demo.core namespace, so happy is resolved as demo.core/happy. When we use lein run, however, observe:
(defn -main [& args]
(println *ns*)
(println (ns-name *ns*)))
with result:
~/expr/demo > lein run
*ns* => #object[clojure.lang.Namespace 0xb625b00 "user"]
(ns-name *ns*) => user
and we see that the *ns* is set to the user namespace and happy cannot be resolved to the Var demo.core/happy unless we fully qualify it either manually or using syntax-quote in the code.
You can find a list of documentation here. Be sure especially to study the Clojure CheatSheet.
For macros, the book Mastering Clojure Macros is also good.
Your macro function doesn't return code, but does the printing immediately. This is very bad style as it has unforeseen consequences.
If you were to use this is a function:
(defn hello [] (Simple))
It prints "Hello" when the function is created. The code being inserted in the function is the result fo println which is nil, thus you have created this:
(defn hello [] nil)
Then if you call hello 3 times none of the calls will no any printing since your macro doesn't produce anything else than nil. If you change your macro to return structure:
;; The quote that makes all the difference
(defmacro Simple [] '(println "Hello"))
Then if will not print anything during the createion of hello, but the expansion would be (println "Hello") and the same fucntion hello would become:
(defn hello [] (println "Hello"))
I'm new to Clojure so this might be obvious.
(println (nil? (resolve 'x)))
(def x 1)
(println (nil? (resolve 'x)))
This prints out
true
true
Why doesn't the second println output false?
According to the examples on ClojureDocs, shouldn't this be the case?
EDIT:
I'm not running this through REPL.
This is how I got there:
Create a project via lein new testing.
After modifications to core.clj, it looks like this:
(ns testing.core
(:gen-class))
(defn -main
[& args]
(println (nil? (resolve 'x)))
(def x 1)
(println (nil? (resolve 'x)))
)
When ran through lein run, output is:
true
true
When I evaluate those expressions in a Clojure REPL, I get true for the first one, and false for the second one. How you are you starting the Clojure REPL? What version of Clojure are you using? Can you reproduce this consistently?
(resolve 'x) try to get a Var named by (bound to) the x symbol. If this Var does not exist, it should return nil. So your assumptions are correct.
If you are coding with a live REPL, remember that code you evaluate stays in memory until you replace it by a new version or manually undefine it.
Here is a visual REPL session from my side showing the correct behavior:
There is something strange about your environment:
~/expr/demo > lein repl
demo.core=> (resolve 'x)
nil
demo.core=> (resolve 'x)
nil
demo.core=> (resolve 'x)
nil
demo.core=> (resolve 'x)
nil
demo.core=> (def x 1)
#'demo.core/x
demo.core=> (resolve 'x)
#'demo.core/x
Try running the following program instead, and read the output carefully. Note that the doc string for the function 'resolve' says that it resolves the symbol in the namespace that is the current value of *ns*, and that is a "dynamic var", which according to the output of the program shown below, is equal to the 'user' namespace by default, different than the namespace where the function is defined, which is the namespace where 'x' is 'def'd.
(ns testing.core
(:gen-class))
(defn -main
[& args]
(println)
(println "before (def x 1)")
(println "*ns*=" *ns*)
(println "(resolve 'x)=" (resolve 'x))
(println "(resolve 'user/x)=" (resolve 'user/x))
(binding [*ns* 'testing.core]
(println "*ns*=" *ns*)
(println "(resolve 'x)=" (resolve 'x))
(println "(resolve 'user/x)=" (resolve 'user/x)))
(def x 1)
(println)
(println "after (def x 1)")
(println "*ns*=" *ns*)
(println "(resolve 'x)=" (resolve 'x))
(println "(resolve 'user/x)=" (resolve 'user/x))
(binding [*ns* 'testing.core]
(println "*ns*=" *ns*)
(println "(resolve 'x)=" (resolve 'x))
(println "(resolve 'user/x)=" (resolve 'user/x))))
Output on my system:
before (def x 1)
*ns*= #object[clojure.lang.Namespace 0x524f3b3a user]
(resolve 'x)= nil
(resolve 'user/x)= nil
*ns*= testing.core
(resolve 'x)= #'testing.core/x
(resolve 'user/x)= nil
after (def x 1)
*ns*= #object[clojure.lang.Namespace 0x524f3b3a user]
(resolve 'x)= nil
(resolve 'user/x)= nil
*ns*= testing.core
(resolve 'x)= #'testing.core/x
(resolve 'user/x)= nil
I'm trying require clojure.algo.monads, I'm a little confused with clojure import/require/use
; at lein...
:main monads.core/-main
:dependencies [[org.clojure/clojure "1.6.0"]
[org.clojure/algo.monads "0.1.5"]])
install deps: lein deps
and this simpele code to test
(ns monads.core
(require clojure.algo.monads))
(defn -main [& args]
(clojure.algo.monads)
(println "Hello, World!"))
lein run
Exception in thread "main" java.lang.ClassNotFoundException: clojure.algo.monads, compiling:(monads/core.clj:6:3)
at clojure.lang.Compiler.analyze(Compiler.java:6464)
at clojure.lang.Compiler.analyze(Compiler.java:6406)
at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3665)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6646)
...
I'm doing something wrong?
The expression (clojure.algo.monads) in your -main function is considered a call to clojure.algo.monads, which should be either a special form, a macro, or a function. However, clojure.algo.monads is a namespace. There is no Java class file corresponding to it. This results in ClassNotFoundException.
I suggest that you require the clojure.algo.monads namespace and refer only limited functions or macros that you want to use. Here is an example.
user> (require '[clojure.algo.monads :refer [domonad maybe-m]])
nil
user> (defn f
[x]
(domonad maybe-m
[a x
b (inc x)]
(* a b)))
#'user/f
user> (f 3)
12
user> (f nil)
nil
EDIT: Turned out I was using require instead of :require in the namespace declaration. With :require, tools.namespace refreshes the logging namespace, and the problem goes away. I still find it curious, however, that the expression (eval `(var ~(symbol "A/func"))) does not work in the situation described below (that is, if B below is not refreshed).
Summary: I'm using tools.namespace. If I have namespaces A and B, and in B do (eval `(var ~(symbol "A/func"))), and (tools.namespace/refresh) and run the code, that works. But if I make a change to A, do (tools.namespace/refresh), so that only A refreshes, then running that expression gives the error: Cannot resolve var: A/func in this context, even though A/func exists. Why?
Longer version:
In my project, I have a logging module/namespace that uses robert-hooke (see below). I'm using tools.namespace to reload my code when I make changes.
The problem is the following: When I want to log (my logging currently just prints) something, I list the functions that I want to log in my logging namespace and do (t.n/refresh). That works. But if I make changes to the the namespaces that contain the functions that I want to log, and do (t.n/refresh) without making changes to the logging namespace, the logging no longer works (for the functions that have been refreshed). As soon as I make a change to logging, so that it too is refreshed by tools.namespace, it starts working again.
So, it's like the vars in namespaces that have been refreshed don't properly get their logging hooks. But I don't understand why.
Below is my logging namespace. I call add-logging-wrappers each time I run my program.
If I add (eval `(var ~(symbol "sv/register-damage"))) inside add-logging-wrappers, that's fine when logging has just been refreshed and the logging works. But those times the logging does not work, that expression causes the error Cannot resolve var: sv/register-damage in this context.
(ns game.logging
(require [robert.hooke :as rh]
[clojure.pprint :as pp]
[game.server.core :as sv]
[game.client.core :as cl]
[game.math :as math]
(game.common [core-functions :as ccfns]
[graphics :as gfx])
(game.server [pathfinding :as pf]))
(:use [game.utils]))
(defn log-println [name type object]
(println (str (current-thread-name) " // " name " " type ":\n"
(with-out-str
(pp/pprint object)))))
(defn print-output [name f & args]
(let [result (apply f args)]
(log-println name "output" result)
result))
(defn print-input [name f & args]
(log-println name "input" args)
(apply f args))
(defn print-call [name f & args]
(println (str (current-thread-name) "//" name))
(apply f args))
(defmacro make-name-var-list [fn-list]
`[~#(for [fn fn-list]
[(str fn) `(var ~fn)])])
(defmacro defloglist [name & fns]
`(def ~name (make-name-var-list [~#fns])))
(defn add-hooks [name-vars & wrappers]
(when (seq wrappers)
(doseq [[name var] name-vars]
(rh/add-hook var (partial (first wrappers) name)))
(recur name-vars (next wrappers))))
(defn get-ns-name-vars [ns-sym]
(-> (the-ns ns-sym) (#(.name %)) ns-interns))
(defn add-hooks-to-ns [ns-sym & wrappers]
(apply add-hooks (get-ns-name-vars ns-sym) wrappers))
(defloglist log-both
sv/distribute-exp ;; <--- things to log
sv/register-damage
sv/give-exp)
(defloglist log-input)
(defloglist log-output)
(defn add-logging-wrappers []
(dorun (->> (all-ns) (map #(.name %)) (mapcat ns-interns) (map second)
(map rh/clear-hooks)))
(add-hooks log-both print-output print-input)
(add-hooks log-input print-input)
(add-hooks log-output print-output))