http://clojure.org/metadata says "Symbols and collections support metadata"
So I try to set metadata to a symbol:
=> a
17
=> (def aa ^a 'x)
=> aa
x
=> (meta aa)
nil
It does not work as I expected.
=> (def aa ^a [])
=> (meta aa)
{:tag 17}
This does.
Is this a mistake in the documentation? If not, can you please explain?
Update after answer by Arthur Ulfeldt: So I understand it as follows. When I wrote
(def aa ^a 'x)
the reader expanded it into
(def aa ^a (quote x))
so the metadata were at the list (quote x), and not at the symbol. When evaluating the def macro, this list got evaluated, leaving us with x, and the metadata were lost.
It works if instead of using the quote reader macro you write out the (quote x) expression and then attach the metadata to the symbol within the quote:
user> (def aa (quote ^unevaluated-symbol x))
#'user/aa
user> (meta aa)
{:tag unevaluated-symbol}
It's worth noting that when you put the symbol with the quote it never gets a chance to be evaluated. if you want it evaluated you can skip the whole quoting and generate the symbol with the symbol function:
user> (def aa (with-meta (symbol "x") {:foo a}))
#'user/aa
user> (meta aa)
{:foo 17}
Related
My ultimate goal is to produce this code with a macro, where word can be any string (without white space):
=> (def word "word")
This is what I have so far. It compiles, but doesn't run.
=> (defmacro mirror [val] `(def (symbol val) val))
Expected behavior:
=> (mirror "michael")
=> (mirror "jackson")
=> michael
"michael"
=> jackson
"jackson"
Actual behavior:
=> (mirror "michael")
Syntax error compiling def at (/tmp/form-init2235651799765014686.clj:1:25).
First argument to def must be a Symbol
From what I understand, (def) is expecting a Symbol as it's first argument, which (symbol val) should return. My guess is that the compiler is checking (def)'s arguments' types before evaluating them, so instead of a Symbol it sees an expression and throws an error.
(defmacro mirror [val] `(def ~(symbol val) ~val))
If val is expected to be a string literal, akond's solution suffices.
If you want to use string-generating expressions, like amalloy does in his comment, you can write:
(defmacro mirror [exp] (let [val (eval exp)] `(def ~(symbol val) ~val)))
Using amalloy's example we have:
=> (def module-name "foo")
#'user/module-name
=> (mirror (str module-name "-test"))
#'user/foo-test
=> foo-test
"foo-test"
This macro evaluates the expression "at compile-time". This means among other things that you cannot use local variables inside it (e.g. (let [suffix "-test"] (mirror (str module-name suffix))) fails). To evaluate it "at run-time" you can write:
(defmacro mirror [exp] `(let [~'val ~exp] (eval `(def ~(symbol ~'val) ~~'val))))
Alternatively, you could avoid macros and def and use intern.
(def a (edn/read-string "(+ 1 3)"))
; => (+ 1 3)
How do I evaluate this resulting list?
(type (first a))
; => cljs.core/Symbol
(= (first a) '+)
; => true
I suppose more generally how would I get from symbol -> function.
And is this a normal practice in clojure? I can't seem to find anything on it. Perhaps I'm not searching with the correct terms.
You'd normally use eval. But in ClojureScript, you'd need the compiler and standard lib available at runtime. This is only possible if you are making use of self-hosted ClojureScript.
If you are in a self-hosted environment (such as Lumo, Planck, Replete, Klipse, etc.), then eval will just work:
cljs.user=> (require '[clojure.edn :as edn])
nil
cljs.user=> (def a (edn/read-string "(+ 1 3)"))
#'cljs.user/a
cljs.user=> (eval a)
4
Otherwise, you can make use of the facilities in the cljs.js namespace to access self-hosted ClojureScript:
cljs.user=> (require 'cljs.js)
nil
cljs.user=> (cljs.js/eval (cljs.js/empty-state)
a {:eval cljs.js/js-eval :context :expr} prn)
{:value 4}
Note that doing this carries some size considerations: The ClojureScript compiler will be brought with your compiled artifacts into the target environment, and you must also avoid using :advanced, ensuring that the entire cljs.core standard lib and associated metadata is available at runtime.
My answer seems to only work in Clojure, not ClojureScript. See the other answer.
I think you may be looking for resolve.
(defn my-simple-eval [expr]
; Cut the function symbol from the arguments
(let [[f & args] (edn/read-string expr)]
; Resolve f to a function then apply the supplied arguments to it
(apply (resolve f) args)))
(my-simple-eval "(+ 1 3)")
=> 4
The arguments must be bare numbers for this to work though. If you want to allow for sub-expressions, you could make it recursive:
(defn my-simple-eval-rec [expr]
(letfn [(rec [[f & args]]
(->> args
(map (fn [arg]
(if (list? arg)
(rec arg) ; Process the sub-expr
arg)))
(apply (resolve f))))]
(rec (edn/read-string expr))))
(my-simple-eval-rec "(+ 1 (+ 2 5))")
=> 8
If this doesn't suffice though, I don't know of any way other than using eval:
(def a (edn/read-string "(+ 1 3)"))
(eval a)
=> 4
or, if the data is available at the time macros are expanded, you could just wrap the call to read-string to have the data interpreted as normal:
(defmacro my-read-string [expr]
(edn/read-string expr))
(my-read-string "(+ 1 3)")
=> 4
I have a question regarding how to define functions/macros which call other macros or special forms but where one of the symbols passed in needs to be dynamic.
The simplest version of this question is described below:
We can define variables using def
(def x 0)
But what if we wanted the name x to be determined programmatically so that we could do the equivalent of?
(let [a 'b]
(our-def a 3)) => user/b
We could try to define a function
(defn defn2 [sym val]
(def sym val))
However it does not do what we want
(def2 'y 1) => #'user/sym
At first it seems like a macro works (even though it seems like it would be unnecessary)
(defmacro def3 [sym val]
`(def ~sym ~val))
(def3 z 2) => user/z
but it is just superficial, because we're really right back where we started with regular def.
(let [a 'b]
(def3 a 3)) => user/a
I can do it if I use eval, but it doesn't seem like eval should be necessary
(defn def4 [sym val]
(eval `(def ~sym ~val)))
(let [a 'b]
(def4 a 4)) => user/b
If there are other built-in commands that could achieve this particular example, they are not really what I am looking for since def is just to show a particular example. There are macros more complicated than def that I might want to call and not have to worry about how they were internally implemented.
First: The right way to do this is to use macro that starts with def... since this is the way people have been doing defs and is of little surprise to the user.
To answer you question: Use intern:
(def foo 'bar)
(intern *ns* foo :hi)
(pr bar) ;; => :hi
(intern *ns* foo :hi2)
(pr bar) ;; => :hi2
If you want to use macros do this:
(def z 'aa)
(defmacro def3 [sym val]
`(def ~(eval sym) ~val))
(def3 z 2)
(pr aa) ;; => 2
Here is a simple example:
(let [^String y "abc"] (meta y)) ; returns nil
There seems to be no metadata at all, why?
According to the doc:
Type hints are metadata tags placed on symbols or expressions that are
consumed by the compiler.
(meta y) returns the metadata of y, not the symbol y.
You can't access the symbol y in the let body. It is only accessed by the evaluator when evaluating the let* special form.
(read-string "^String y")
;-> y ;; a symbol
(meta *1)
;-> {:tag String}
So I thought it would be a nice idea to name a function that calculates the exponential ^, but it seems like the caret actually does something special, as the Clojure REPL generates an error when evaluating '^. Googling mostly gave me this, so I was wondering what the actualy use for the caret in Clojure is.
(Also, would it be possible after all to name a function ^?)
^ is "the meta character" it tells the reader to add the symbol starting with ^ as metadata to the next symbol (provided it is something that implements IMetas)
user=> (def x ^:IamMeta [1 2 3])
#'user/x
user=> x
[1 2 3]
user=> (meta x)
{:tag :IamMeta}
user=>
You can learn a lot about how clojure works under the hood by looking at the meta of things, for instance functions:
user=> (meta foo)
{:ns #<Namespace user>,
:name foo, :file "NO_SOURCE_PATH",
:line 5, :arglists ([s])}
this is very often used for type hints
(defn foo [^String s] (.charAt s 1))
it is generally a good idea to turn on reflection warnings (set! *warn-on-reflection* true) and then add type hints until the warnings go away. without these Clojure will look up the type of the function operands at run-time, which saves you the trouble of fussing with types though at a slight cost.
PS: My next favorite reader character is the "dispatch" character #, it is well worth learning about it next :)
PPS: this is different in clojure 1.2.x vs clojure 1.3.x
in Clojure 1.2.1 metadata does not compose when you use the meta-character:
user=> (def foo ^:foo ^:bar [1 2 3])
#'user/foo
user=> (meta foo)
{:tag :foo}
and in 1.3 it "does the right thing" and also keywords are options instead of "tags":
user=> (def foo ^:foo ^:bar [1 2 3])
#'user/foo
user=> (meta foo)
{:foo true, :bar true}
It seems to me that the answer to your question is, unfortunately, no. In Clojure, you cannot name a function ^.
I tried the following in the REPL:
user=> (println \^)
^
nil
This seems to imply that you can escape the carat (^) with a backslash. However, if I try to declare a function using \^ as a name then I get an error message:
user=> (defn \^ [n e] (cond (= e 0) 1 :else (* n (\^ n (- e 1)))))
IllegalArgumentException First argument to defn must be a symbol
clojure.core/defn (core.clj:277)
The same code works with a regular text name:
user=> (defn exp [n e] (cond (= e 0) 1 :else (* n (exp n (- e 1)))))
#'user/exp
user=> (exp 3 3)
27
I would be delighted if someone with better Clojure-fu than mine could prove me wrong! :)