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)))
Related
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...
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=>
In clojure, is it possible to execute multiple expressions in a cond case, without do or let form. In Racket, one may do things as:
(cond
(> a 0) ((display a) (display (* a a))
(= a 0) ...
...
Another form that contains an implicit do is when, so “yes,” you could achieve this without do or let:
(cond
(> a 0) (when true
(println a)
(println (* a a))))
But, of course, that's contrived and the real answer to your question is “no.”
Each clause has a pair of forms: A test form and an expression form. You can't have multiple expression forms in a cond clause—you'd need to further wrap them in a single form such as do. They are referred to as expression forms because usually their value is of interest (in a purely functional context) because it is the value of the expression in the clause with the first truthy test that the entire cond form evaluates to.
But, if you are using cond as a way to achieve conditional side effects, perhaps do is a good reinforcement of the intent:
(cond
(> a 0) (do (println a)
(println (* a a))))
I am reading Land of Lisp by Conrad Barski and I am a bit confused on the use of the 'if' command (to name a few)..
So, I understand that writing if '() means that the list is empty and condition is false and if '(1) means the list is non empty and condition is true.
The question is how does lisp know which expression to choose and output based on the nature (True/False) of the if(1) condition? for example in the code below the statement if '(1) is true but then how and why does lisp choose expression I-AM-TRUE as an output?
(if '(1)
'i-am-true
'i-am-false)
I-AM-TRUE
similarly how and why does it output How-does-this-happen in example below..
(if '(1)
'how-does-this-happen
'any-guesses)
HOW-DOES-THIS-HAPPEN
The structure of an if statement is:
(if condition true-stament false-statement)
In other words, the first statement (true-statement) always happens when condition evals to true, and the second statement (false-statement) happens when the condition evals to false.
if special form is used like this:
(if predicate consequent alternative)
In Common Lisp the false value is the empty list nil, represented by either nil or (). The truth value is T and every other value that is not nil. If the predicate evaluates anything except nil it's true and the consequent gets evaluated. If not the alternative is evaluated.
(defun my-not (x)
(if x nil t))
(my-not ()) ; ==> t
(my-not nil) ; ==> t
(my-not '()) ; ==> t
(my-not 'nil) ; ==> t
(my-not t) ; ==> nil
(my-not 'this-is-atruth-value) ; ==> nil