I'm trying to run this code with lein run, but I get this error:
java.lang.RuntimeException: Unable to resolve symbol: pd in this context
The strange thing is, lein repl and calling (-main) works just fine, no error.
What am I doing wrong?
(ns test.core)
(defn pd [num denom]
(if (zero? denom)
0
(/ num denom)))
(defn -main []
(println
((eval
(list 'fn
'[x y]
'(pd x y)))
3 4)))
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 want to play around and develop expressions based on local variables by placing a repl (with clojure.main/repl) inside a function body:
(ns something)
(defn myfunc [ p ]
(let [local (+ p 10)]
(clojure.main/repl)
(+ local 100)))
(myfunc 666)
When I executed this, the repl starts ok, but the parameters of the function and local let-bindings do not seem to be visible in the prompt:
something=> p
CompilerException java.lang.RuntimeException: Unable to resolve symbol: p in this context
something=> local
CompilerException java.lang.RuntimeException: Unable to resolve symbol: local in this context
I have been able to pass the values by creating new ^:dynamic vars and setting their values locally with binding, but this is quite complex and requires separate binding for each local variable:
(def ^:dynamic x)
(defn myfunc [ p ]
(let [local (+ p 10)]
(binding [x local]
(clojure.main/repl))
(+ local 100)))
Is there simpler way to pass/access local values in such local repl? Or is there some better way to do access the local variables from non-local repl, such as the "lein repl"?
Using the :init hook, you can define arbitrary vars in the REPL namespace.
(defn myfunc [p]
(let [local (+ p 10)]
(clojure.main/repl :init #(do (def p p) (def local local)))
(+ local 100)))
Here's a repl macro to make adding a breakpoint easier:
(defmacro locals []
(into {}
(map (juxt name identity))
(keys &env)))
(defn defs [vars]
(doseq [[k v] vars]
(eval (list 'def (symbol k) (list 'quote v)))))
(defmacro repl []
`(let [ls# (locals)]
(clojure.main/repl :init #(defs ls#))))
Now you can just drop in (repl):
(defn myfunc [p]
(let [local (+ p 10)]
(repl)
(+ local 100)))
I don't know a good answer for using the repl, but I favor using good old-fashioned printouts. This is facilitated by the spyx, let-spy, and let-spy-pretty macros:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(defn myfunc [ p ]
(spyx p)
(let-spy [local (+ p 10)]
(+ local 100)))
(dotest
(spyx (myfunc 666)))
with result:
p => 666
local => 676
(myfunc 666) => 776
Documentation on spyx & friends is here in the README, and there is also full API documentation on GitHub pages.
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
This code is from Clojure in action listing 3.5. When I try to run it i get the following error:
Can't dynamically bind non-dynamic var: joy.q/twice
Am I doing something wrong or has Clojure changed its binding rules since this book was printed?
(defn twice [x]
(println "original function")
(* 2 x))
(defn call-twice [y]
(twice y))
(defn with-log [function-to-call log-statement]
(fn [& args]
(println log-statement)
(apply function-to-call args)))
(call-twice 10)
(binding [twice (with-log twice "Calling the twice function")]
(call-twice 20))
From the binding documentation:
As of Clojure 1.3, vars need to be explicitly marked as ^:dynamic in order for
them to be dynamically rebindable
So you need:
(defn ^:dynamic twice [x]
(println "original function")
(* 2 x))
When using the repl, sometimes you want to destroy a variable because it somehow get in the way of your programming (most usually namespace collisions).
Is there a way to destroy a variable in clojure?
user>(def x 1)
#'user/x
user>(aggressive-destroy! x)
nil
user>x
Unable to resolve symbol: x in this context
ns-unmap
user=> (def my-var "this is my-var!")
#'user/my-var
user=> (println my-var)
this is my-var!
nil
user=> (ns-unmap 'user 'my-var)
nil
user=> (println my-var)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: my-var in this context, compiling:(NO_SOURCE_PATH:13)
user=>