I don't understand how to get the full macro expansion.
With this code
(when true (when true true))
I would like to get the full macro expansion
(if true (do (if true (do true)))
But I can't
I understand macroexpansion-1 will resolve the first level of expansion :
(macroexpand-1 '(when true (when true true)))
(if true (do (when true true)))
But why when I call again macroexpand-1 (that's what should do macroexpand) :
(macroexpand-1 '(if true (do (when true true))))
I got the exact same result ?
(if true (do (when true true)))
I was expecting a full macro expansion.
Does macro expansion only works with top level forms ?
I'm aware of an expand-all function in the clojure.walk namespace, so I
suppose macroexpand doesn't work on nested structures. Am I right ?
You are right.
See also https://clojuredocs.org/clojure.core/macroexpand
Where it states :
Note neither macroexpand-1 nor macroexpand expand macros in subforms.
And indeed macroexpand-all does the recursive expansion :
> (clojure.walk/macroexpand-all '(when true (when true true)))
(if true (do (if true (do true))))
See also https://clojuredocs.org/clojure.walk/macroexpand-all
where it states :
Recursively performs all possible macroexpansions in form.
Your example
(macroexpand-1 '(if true (do (when true true))))
might confuse you, but it does as the docs tell :
(macroexpand-1 form) If form represents a macro form, returns its
expansion, else returns form.
So since 'if' is not a macro, it just returns if, without going into subforms...
Related
I am a bit puzzled with the behavior of if. The following code works fine:
(if true
(let [x "whatever"]
(println "TRUE 1")
(println "TRUE 2")))
returns:
TRUE 1
TRUE 2
nil
But if the let expression is removed:
(if true
(
(println "TRUE 1")
(println "TRUE 2")))
it returns a NullPointerException as well:
TRUE 1
TRUE 2
NullPointerException user/eval8051 (NO_SOURCE_FILE:4)
I suspect it is due to the println returning a nil. But then why does it work when a let is introduced? Is there a better way to do this?
The key part is this block
((println "TRUE 1")
(println "TRUE 2"))
What this does is evaluate the printlns, turning the expression into this:
(nil nil)
And then, because of the additional parenthesis, it tries to call nil as a function, with nil as the argument. Since nil is not a function, it throws the exception. The reason it worked in the first case was because it had the let to evaluate instead. Since a let will evaluate every expression in its body (and doesn't try to treat the results as a function), it behaves correctly.
If you want to evaluate multiple expressions, you should use do
(if true
(do (println "TRUE 1")
(println "TRUE 2")))
or, since there's no "else" part, you can just use when
(when true
(println "TRUE 1")
(println "TRUE 2"))
The important thing to remember is that in Clojure, unlike in C-style languages, you can't just add parenthesis around expressions without changing the meaning. If you wrap something in parenthesis (without quoting it), it's going to try and evaluate it as a function invocation.
The way I understand a scheme if-statement is that the first condition is when the if-statement is true, and the second statement is when it is false. What if I want several conditions for when the statement proves true?
An example:
(if (= a b)
(set! ([a 2])) // This shall happen when true
(set! ([b 4])) // This shall happen when true
(set! ([a b])) // This shall happen when NOT true
Is it possible to do something like that?
You can try to use begin in an if statement. like so:
(if (something)
(begin (foo)
(bar)))
Why do the following statements return different results? And further, how would one write the second statement to receive the expected result of false?
(clojure.core/and false true)
=> false
((resolve 'clojure.core/and) false true)
=> true
The kind folks at #clojure on freenode helped me with an answer.
First, one should try to avoid resolving macros at run-time.
Second, the macro function is implemented as a function that takes in two parameters, besides of the any (&) args. Hence, the correct way to write the second statement above would be
((resolve 'clojure.core/and) nil nil false true) =>
**(clojure.core/let [and__3973__auto__ false] (if and__3973__auto__ (clojure.core/and true) and__3973__auto__))**
Since we are still using a macro, it simply will expand it to code, instead of returning an actual value.
The reason AND is implemented as a macro, is to make short-circuiting possible.
You can see from the REPL:
(defmacro and
"Evaluates exprs one at a time, from left to right. If a form
returns logical false (nil or false), and returns that value and
doesn't evaluate any of the other expressions, otherwise it returns
the value of the last expr. (and) returns true."
{:added "1.0"}
([] true)
([x] x)
([x & next]
`(let [and# ~x]
(if and# (and ~#next) and#))))
Without the macro, an AND function would evaluate all of the predicate given to it without short-circuiting.
In my particular case, this is exactly what I needed; both for AND and OR non short-circuiting functions.
Here follows both functions in case anyone ever needs them:
(defn and* [& xs] (every? identity xs))
(defn or* [& xs] (not= (some true? xs) nil))
Strange as it may sound, I am looking for function versions of the and and or macros in Clojure.
Why? For one I am curious.
Second, I want to use or in precondition and postcondition checks. This does not work:
(defn victor
[x]
{:post (or (nil? %) (vector %))}
;; ...
)
I want the postcondition to check to see if victor returns a vector or nil, but it fails:
#<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/or, compiling:(test/test.clj:10:1)>
I don't think bit-and and bit-or are quite what I'm looking for.
Update: This syntax works without an error:
(defn victor
[x]
{:post [(or (nil? %) (vector %))]}
;; ...
)
I'm still curious if functions exist, though.
I think the standard method is simply to wrap and and or in functions, e.g. (fn [x y] (or x y)). In some contexts, another function will work. For example, a note in the clojure docs for and suggests using (every? identity [true false]). some, not-every?, and not-any? can be used in a similar way.
In general, and and or functions would be undesirable because they cannot use short-circuiting. Consider the following code:
(and false some-expensive-fn)
(or true some-expensive-fn)
With and and or as macros the above code won't execute some-expensive-fn, because it is unnecessary to determine the overall truth value of the expression. In function expressions the arguments are evaluated before being passed to the function, but in macros they are not.
#Triangle Man is right. Short-circuiting won't work, but nevertheless you can define your own function versions:
user=> (defn && [x y] (and x y))
#'user/&&
user=> (&& true false)
false
user=> (&& true true)
true
user=> (defn || [x y] (or x y))
#'user/||
user=> (|| true false)
true
user=> (|| true true)
true
user=> (|| false false)
false
user=>
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.)