I'm starting with Clojure and trying to bind (or true) to be (true). I get the following error:
CompilerException java.lang.ClassCastException: java.lang.Boolean cannot be cast to clojure.lang.IFn, compiling:(myproject\core.clj:8:26)
Here's the code:
(declare ^:dynamic or)
(binding [or true] (true))
If I just do
(binding [or true] (true))
I get:
CompilerException java.lang.IllegalStateException: Can't dynamically bind non-dynamic var: clojure.core/or, compiling:(myproject\core.clj:5:30)
true is not a function. It shouldn't be in parenthesis.
(declare ^:dynamic or)
(binding [or true] true)
Note that or already refers to clojure.core/or. You could name your var or- instead.
Related
I have a local variable that I must store some texts as a list/vector.
I want to add values to these vector according to some conditions, so what I wanna do is just add values to the vector and in the end have a updated version of this vector
But when I try to use the !swap I always get an error.
I've tried these two options:
(do
(let
[error-list ()]
(println (conj error-list "test"))
(swap! error-list conj "test2")))
The result:
(test)
Exception in thread "main" java.lang.ClassCastException: class clojure.lang.PersistentVector cannot be cast to class clojure.lang.IAtom (clojure.lang.PersistentVector and clojure.lang.IAtom are in unnamed module of loader 'app')
And:
(do
(let
[error-list []]
(println (conj error-list "test"))
(swap! error-list conj "test2")))
The result:
[test]
Exception in thread "main" java.lang.ClassCastException: class clojure.lang.PersistentList$EmptyList cannot be cast to class clojure.lang.IAtom (clojure.lang.PersistentList$EmptyList and clojure.lang.IAtom are in unnamed module of loader 'app')
That is not a local variable, that is a let binding. You have bound the name error-list to the value '() in the first snippet and [] in the second.
swap! is a function for updating the value of an atom. You do not have an atom, you have (first snippet) a List and (2nd snippet) a Vector. You can wrap either of these in an Atom to allow for mutable state using the atom function.
(do
(let
[error-list (atom [])]
(println (swap! error-list conj "test"))
(swap! error-list conj "test2")
#error-list))
[test]
["test" "test2"]
user=>
I could not set my dynamic var's value to new one.
(def *pop* true)
(set! *pop* false)
=> IllegalStateException Can't change/establish root binding of: *pop* with set clojure.lang.Var.set (Var.java:221)
Also I've added ^:dynamic, which did not work either.
(def ^:dynamic *pop* true)
(set! *pop* false)
=> IllegalStateException Can't change/establish root binding of: *pop* with set clojure.lang.Var.set (Var.java:221)
But on the other hand this code works,(clojure core's var -> *warn-on-reflection*)
(set! *warn-on-reflection* true)
=> true
*warn-on-reflection*
=> true
(set! *warn-on-reflection* false)
=> false
*warn-on-reflection*
=> false
Dynamic vars can only be set! inside a binding scope. So just calling set! on *pop* won't work - you need to be in the runtime dynamic scope of a binding somewhere in the call stack above.
(def ^:dynamic *pop* true)
(binding [*pop* *pop*] ;; defaulted to the root binding value
(set! *pop* false) ;; ok, because in dynamic binding scope
(println *pop*)) ;; prints "false" (inside per-thread dynamic binding)
(println *pop*) ;; prints "true" (root value)
Note that the "dynamic scope" part of it means that within binding you can make arbitrary nested calls and still have access to set and read the per-thread value of *pop*.
Regarding *warn-on-reflection*, this looks like special behavior but it's actually exactly the same, except hidden from view. The REPL itself creates a dynamic binding scope around the eval of each REPL statement with bindings for a hard-coded set of dynamic vars, of which *warn-on-reflection* is one. You can find that set of bindings here.
You can use alter-var-root to change the root vars.
user=> (def *pop* true)
Warning: *pop* not declared dynamic ...
#'user/*pop*
user=> (alter-var-root #'*pop* (constantly false))
false
user=> *pop*
false
I'm experimenting with ns in Clojure, here's what I try:
user=> (in-ns 'some-ns)
#<Namespace some-ns>
some-ns=> (def aa 100)
#'some-ns/aa
some-ns=> (in-ns 'user)
#<Namespace user>
user=> (= some-ns/aa 100)
true
user=> (= user/aa 100)
CompilerException java.lang.RuntimeException: No such var: user/aa, compiling:(NO_SOURCE_PATH:5:1) ;this works as expected
user=> (defn function [] (in-ns 'some-other-ns) (def cc 100) (in-ns 'user))
#'user/function
user=> (function)
#<Namespace user>
user=> (= some-other-ns/cc 100)
CompilerException java.lang.RuntimeException: No such var: some-other-ns/cc, compiling:(NO_SOURCE_PATH:8:1)
user=> (= user/cc 100)
true
I'm confused, why it doesn't work in function? Also, I tried following:
user=> (binding [*ns* (create-ns 'some-a-ns)] (def dd 100))
#'user/dd
user=> (= some-a-ns/dd 100)
CompilerException java.lang.RuntimeException: No such var: some-a-ns/dd, compiling:(NO_SOURCE_PATH:11:1)
user=> (= user/dd 100)
true
according to clojure doc
Creates and interns or locates a global var with the name of symbol and a namespace of the value of the current namespace (*ns*).
what I'm missing?
PS. I know I can use (intern 'some-ns 'a 100), but what I really want is a generic function/macro to do like
(with-ns 'some-ns (def a 100))
(= some/a 100)
intern is the correct solution and you can use it in any functions / macros of your own. (Functions can call intern; macros can expand to code calling intern.)
def should only ever be used directly at top level or nested within top-level forms where it will be immediately executed as soon as the top-level form is. So, def in let is fine, def inside a function is not.
def receives special handling from the compiler in that the Vars defined by def forms are actual created as soon as the def is compiled; the initial bindings specified in def forms are installed, however, if and when the flow of control actually reaches the def form. This explains why the binding example doesn't work -- it is the compile-time value of *ns* which counts, while the binding introduced by this binding form will come into effect at run time.
Finally, if you absolutely insist on using def forms to create Vars at runtime, the way to do it is with eval:
(binding [*ns* some-ns]
(eval '(def foo 1)))
;; some-ns/foo comes into existence with a root binding of 1
Note that here def does occur at top-level and will be immediately executed after compilation.
I wanna get the string representation of a variable. For example,
(def my-var {})
How to get the string "my-var" from symbol my-var? And
(defn my-fun [] ...)
How to get the string "my-fun" from function my-fun?
user=> (def my-var {})
#'user/my-var
user=> (defn my-fun [] )
#'user/my-fun
user=> (name 'my-var)
"my-var"
user=> (name 'my-fun)
"my-fun"
user=> (doc name)
-------------------------
clojure.core/name
([x])
Returns the name String of a string, symbol or keyword.
nil
Every Var in Clojure has :name metadata attached.
user> (def my-var {})
#'user/my-var
user> (:name (meta #'my-var))
my-var
user> (let [a-var #'my-var]
(:name (meta a-var)))
my-var
However, usually if you already have the Var, then you already know the name anyway, and usually you don't use Vars in a program (i.e., you just pass my-var or my-fun rather than #'my-var and #'my-fun).
There's nothing to get the Var (or var-name) of a function or a value that happens to be the value of some Var. A Var knows its value, but not the other way round. That of course makes sense since, e.g., the very same function may be the value of zero (for local functions) or multiple vars.
How about this?
(defn symbol-as-string [sym] (str (second `(name ~sym)))
=> (def my-var {})
#'user/my-var
=> (symbol-as-string my-var)
"my-var"
=> (symbol-as-string 'howdy)
"howdy"
Doesn't work for function or macro names though, maybe someone can help me
=> (symbol-as-string map)
"clojure.core$map#152643"
=> (symbol-as-string defn)
java.lang.Exception: Can't take value of a macro: #'clojure.core/defn (NO_SOURCE_FILE:31)
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=>