As an exercise in manipulating code as data I wanted to take a piece of Clojure code and change all the bar calls for foo calls. But I came across a struggle in checking for function equality. My problem is:
(= foo foo) ;returns true
(= foo (first `(foo))) ;returns false
What is the proper way of checking for the second equality?
The reason is that you quote the list:
> (= 'foo (first '(foo)))
true
> (= 'foo (first (list foo)))
false
> (= foo (first (list foo)))
true
The answer is that symbols in clojure are special: they automatically perform variable substitution.
If your original problem had used a keyword or string, it would have worked perfectly:
(= "foo" (first ["foo"]))) => true
(= :foo (first [:foo ]))) => true
(= "foo" (first '("foo") ))) => true
(= :foo (first '(:foo ) ))) => true
Notice that we need to quote the list to turn off it's default meaning of "function call".
Similarly, a symbol has a default interpretation of "variable substitution":
(def doh 5)
(= 5 doh) => true
If we want to treat the symbol doh as a piece of data, we need to quote it to turn off the default behavior:
(= (symbol "doh") 'doh) => true
NOTE: Using a single-quote recursively quotes everything inside the quoted form. That means we can turn-off the "function-call" behavior of the parentheses and the "variable substitution" behavior of a symbol with just one single-quote character:
(= 'foo (first '(foo))) => true
(= (symbol "foo") (first '(foo))) => true
Note that the symbol function will convert a regular text string into a symbol.
Finally, note that the single quote character is just a shortcut in the Clojure Reader for a "function" named quote:
(= (quote foo) (first '(foo))) => true
quote is actually a special form, not a function. This means it is built into the compiler and does not follow the normal rules for a function. Otherwise, it would have automatically performed variable substitution and the above would have looked like:
(= (quote 5) (first '(foo))) => false
Note that (quote 5) and 5 are both the same to the compiler. Since the integer 5 is not equal to the first item of a length-1 list containing the symbol foo, the expression is false.
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.
I've started learning Clojure this week. I'm working my way through the conditional koans and don't understand the following assertions:
"Some of them leave you no alternative"
(= [] (if (> 4 3)
[]))
"And in such a situation you may have nothing"
(= nil (if (nil? 0)
[:a :b :c]))
The second one does what I would expect -- the condition evaluates to false-- [EDIT: Actually, it's true and I'm just still not used to 'operator-first' reasoning!], if tries to return the second alternative, finds none, and so returns nil. So, why doesn't the first return nil? Is it because an empty structure is 'close enough' to nil?
Because the first if evaluates to true (as 4 is indeed greater than 3), so else-clause is irrelevant. It returns the then-clause, which is defined and equal to [].
I'm having trouble with a clojure project, and I cannot seem to find an answer. I am trying to compare two symbols:
'x 'y
But when I use:
(= ('x 'y))
It returns true. The same with:
(identical? 'x 'y)
I have found that identical compares memory addresses, but I have not found why 'x and 'y when compared return true? I have not seen a question like this, most of the other posts compare numbers.
You are comparing a list of symbols to nothing. If you only pass one argument to =, it returns true by default. Just remove the parentheses around the symbols and then you'll be comparing the symbols themselves. (= 'x 'y).
(= nil) ; => true
('x 'y) ; => nil
('x #{'x}) ; => 'x
('x #{'z} :one) ; => :one
(instance? clojure.lang.IFn 'x) ; => true
In Common Lisp you use the (null x) function to check for empty lists and nil values.
Most logically this maps to
(or (nil? x) (= '() x))
In clojure. Can someone suggest a more idiomatic way to do it in Clojure?
To get the same result for an empty list in Clojure as you do in Common Lisp, use the empty? function. This function is in the core library: no imports are necessary.
It is also a predicate, and suffixed with a ?, making it a little clearer what exactly you're doing in the code.
=> (empty? '())
true
=> (empty? '(1 2))
false
=> (empty? nil)
true
As j-g faustus already noted, seq can be used for a similar effect.
seq also serves as test for end,
already idiomatic
(when (seq coll)
...)
From clojure.org lazy
It works because (seq nil) and (seq ()) both return nil.
And since nil means false, you don't need an explicit nil test.
Given a list of names for variables, I want to set those variables to an expression.
I tried this:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
...but this yields the error
java.lang.Exception: First argument to def must be a Symbol
Can anyone show me the right way to accomplish this, please?
Clojure's "intern" function is for this purpose:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
In response to your comment:
There are no macros involved here. eval is a function that takes a list and returns the result of executing that list as code. ` and ~ are shortcuts to create a partially-quoted list.
` means the contents of the following lists shall be quoted unless preceded by a ~
~ the following list is a function call that shall be executed, not quoted.
So ``(def ~(symbol x) 666)is the list containing the symboldef, followed by the result of executingsymbol xfollowed by the number of the beast. I could as well have written(eval (list 'def (symbol x) 666))` to achieve the same effect.
Updated to take Stuart Sierra's comment (mentioning clojure.core/intern) into account.
Using eval here is fine, but it may be interesting to know that it is not necessary, regardless of whether the Vars are known to exist already. In fact, if they are known to exist, then I think the alter-var-root solution below is cleaner; if they might not exist, then I wouldn't insist on my alternative proposition being much cleaner, but it seems to make for the shortest code (if we disregard the overhead of three lines for a function definition), so I'll just post it for your consideration.
If the Var is known to exist:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
So you could do
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(If the same value was to be used for all Vars, you could use (repeat value) for the final argument to map or just put it in the anonymous function.)
If the Vars might need to be created, then you can actually write a function to do this (once again, I wouldn't necessarily claim this to be cleaner than eval, but anyway -- just for the interest of it):
(defn create-var
;; I used clojure.lang.Var/intern in the original answer,
;; but as Stuart Sierra has pointed out in a comment,
;; a Clojure built-in is available to accomplish the same
;; thing
([sym] (intern *ns* sym))
([sym val] (intern *ns* sym val)))
Note that if a Var turns out to have already been interned with the given name in the given namespace, then this changes nothing in the single argument case or just resets the Var to the given new value in the two argument case. With this, you can solve the original problem like so:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Some additional examples:
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar
user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
; Var user/baz is unbound.
; It does exist, though!
;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
Evaluation rules for normal function calls are to evaluate all the items of the list, and call the first item in the list as a function with the rest of the items in the list as parameters.
But you can't make any assumptions about the evaluation rules for special forms or macros. A special form or the code produced by a macro call could evaluate all the arguments, or never evaluate them, or evaluate them multiple times, or evaluate some arguments and not others. def is a special form, and it doesn't evaluate its first argument. If it did, it couldn't work. Evaluating the foo in (def foo 123) would result in a "no such var 'foo'" error most of the time (if foo was already defined, you probably wouldn't be defining it yourself).
I'm not sure what you're using this for, but it doesn't seem very idiomatic. Using def anywhere but at the toplevel of your program usually means you're doing something wrong.
(Note: doall + for = doseq.)