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))
Related
I want to write an ACL module by writing a macro, this macro is to check the result of each function call in the macro, if one return false, then the ACL will fail without run the following function call. If one return true and there are still function calls to check, then check the following until the last one.
(defmacro checks
[head & tail]
`(let [status# ~head]
(if (and (true? status#)
(seq '~tail))
(checks ~#tail)
status#)))
I will call this macro like this:
(checks (module1 args) (module2 args))`
but this will fail for (check ~#tail) in the macro definition. The problem is that I want to Unquote Splicing the list but without calling each function in the list.
I have found the way to solve this issue:
(defmacro checks
[head & tail]
(let [sym (gensym)]
`(let [~sym ~head]
(if ~sym
~(if tail
`(checks ~#tail)
sym)
~sym))))
use syntax unquote again on outer the (checks ~#tail) form.
The problem is that you are generating the code for the recursive call to the macro even though there is no argument.
(macroexpand-1 '(checks 1))
=>
(clojure.core/let
[status__1973__auto__ 1]
(if
(clojure.core/and (clojure.core/true? status__1973__auto__) (clojure.core/seq (quote nil)))
(user/checks)
status__1973__auto__))
The inner macro call fails because it needs at least one argument. No matter how many arguments you supply to the macro, its expansion eventually generates the failing call.
You need to establish whether there is anything in tail before generating the recursive call to checks:
(defmacro checks
[head & tail]
(if-not tail
head
`(let [status# ~head]
(if (true? status#)
(checks ~#tail)
status#))))
Now
(macroexpand-1 '(checks 1))
=> 1
(checks 1)
=> 1
And
(macroexpand-1 '(checks 1 2 3))
=>
(clojure.core/let
[status__2010__auto__ 1]
(if (clojure.core/true? status__2010__auto__) (user/checks 2 3) status__2010__auto__))
Furthermore
(checks 1 2 3)
=> 1
(checks true true 3)
=> 3
As #PiotrekBzdyl's comment suggests, this is just an and macro that treats anything other than true as false.
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...
Is it possible to remove the let statement / avoid the intermediate 'x' in the following code?:
(let [x (f a)]
(when (pred? x) x))
I bumped into this problem in the following use case:
(let [coll (get-collection-somewhere)]
(when (every? some? coll) ; if the collection doesn't contain nil values
(remove true? coll))) ; remove all true values
So if the collection is free of nil values, only not-true values remain, like numbers, strings, or whatever.
So, I'm looking for something like this:
(defn pass-if-true [x pred?]
(when (pred? x) x))
Assuming that you don't want to define that pass-if-true function, the best you can do is an anonymous function:
(#(when (every? some? %)
(remove true? %))
(get-collection-somewhere))
You could also extract the predicate and transformation into parameters:
(#(when (%1 %3) (%2 %3))
(partial every? some?)
(partial remove true?)
(get-collection-somewhere))
The let form is necessary to prevent your collection-building function from running twice:
(f a) or (get-collection-somewhere)
This is a typical idiom and you are doing it correctly.
Of course, you don't need the let if you already have the collection and are not building inside this expression.
However, you may wish to see when-let:
https://clojuredocs.org/clojure.core/when-let
It can save some keystrokes in some circumstances, but this isn't one of them.
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.)