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
Related
The book Living Clojure explains that the type nil is treated the same as logical false.
So I expected (false? nil) to return true, which it doesn't. (true? nil) also doesn't. Both return false, which makes me think that Clojure treats nil neither as true nor false.
On the other hand, (not nil) evaluates to true. So I'm a bit confused.
The distinction is testing for logical truth, versus the values themselves.
The values nil and false are treated as logically false in Clojure. All other values are treated as logically true.
The predicates false? and true? test explicitly for the values false and true respectively, as you have noted. These predicates are not often used in Clojure.
According to the documentation of false?:
Returns true if x is the value false, false otherwise.
So the function checks if the parameter equals the value false instead of checking if it is logically false.
In Clojure, all values are either logically true or logically false, so they can be used in conditional expressions. The only logically false values are nil and false.
There are some good answers already.
People sometimes use the terms falsey (nil and false) and truthy (all other values) to describe Clojure values.
It is sometimes handy to coerce values into Boolean true or false. I even wrote a handy function for this:
(defn truthy?
"Returns true if arg is logical true (neither nil nor false); otherwise returns false."
[arg]
(if arg true false))
(defn falsey?
"Returns true if arg is logical false (either nil or false); otherwise returns false. Equivalent
to (not (truthy? arg))."
[arg]
(if arg false true))
These are sometimes convenient when filtering values or constructing a vector of true/false values.
Later, I discovered Clojure already had a function boolean which does the same thing as truthy?.
Be sure to see this list of documentation sources, especially the Clojure CheatSheet. Enjoy!
The book Living Clojure explains that the type nil is treated
the same as logical false.
First, nil is a value - not a type.
Its type is nameless.
Any reference (object) type can have it as a value.
Second, nil and false are distinct values. You can easily write code that treats them differently:
(map #(case %, nil 1, false 2) [nil false])
=> (1 2)
And nil, for example, puns to an empty sequence,
(count nil)
=> 0
whereas false does not
(count false)
Execution error ...
It is as the first argument to if that nil is equivalent to false.
Paraphrasing the official document:
(if test then else?)
... evaluates test, then ...
if it is nil or false, evaluates and yields else;
otherwise evaluates and yields then.
If else is not supplied, it defaults to nil.
All of the other conditionals (when, if-let, cond,
...) follow the same logic:
nil and false constitute logical falsity;
everything else constitutes logical truth.
As for the predicate function false?, it might have been defined ...
(defn false? [x]
(case x, false true, false))
... which, for any argument but the exact value false, returns false.
By the way, the Clojure values false and true are the Java objects Boolean/FALSE and Boolean/TRUE:
Boolean/FALSE
=> false
(if Boolean/FALSE 1 2)
=> 2
(type false)
=> java.lang.Boolean
I am in the process of learning Clojure, through "Clojure for the Brave and True".
In macro lessons, I was trying the below macro,
(defmacro report
[to-try]
`(let [result# ~to-try]
(if result#
(println (quote ~to-try) "was successful:" result#)
(println (quote ~to-try) "was not successful:" result#))))
And below are couple of my experiments with the macro and the respective outputs.
1
(map #(report %) ['(= 1 2) '(= 1 1)])
; p1__26622# was successful: (= 1 2)
; p1__26622# was successful: (= 1 1)
2
map #(report %) ['false 'true])
; p1__26612# was not successful: false
; p1__26612# was successful: true
And my questions are,
Why in the former case the macro printed true for both values?
In my understanding the second is exactly equivalent to the former. But why it gives a different result?
Why in the former case the macro printed true for both values?
Your report macro is receiving quoted lists as inputs, not expressions that can be evaluated to true/false. Any list is truthy, even if it contains an expression that would evaluate to false. This would give you the expected result:
(report (= 1 2)) ;; evaluates to false
In my understanding the second is exactly equivalent to the former. But why it gives a different result?
It's not exactly equivalent because the first example is examining lists and the second is examining quoted booleans. Your second example evaluates 'false as false because that's how if treats it:
(if 'false 0 1) => 1
I've noticed in Scheme, Racket, and Clojure that the expression (using Clojure here) (and true '()) evaluates to (), and (and '() true) evaluates to true. This is true not only for the empty list, but for any list.
But in GNU CLISP and Emacs Lisp, (and t '()) evaluates to nil and (and '() t) evaluates to nil also, but (and t '(1 2 3)) evaluates to (1 2 3) and (and '(1 2 3) t) evaluates to t.
What is going on here?
In the first group of languages, the empty list is not treated as 'falsey' and is instead treated as a 'truthy' value. In scheme and racket, #false is the only false value so even though '() is null, null is not false; in clojure the empty list is not the same as nil, so it is 'truthy' there as well.
In the second group, the empty list is a synonym for nil and is treated as false, leading the condition to return nil. A list with elements however is not the same as nil, and thus is treated as a truthy value again.
The final piece of the puzzle is that and returns the last truthy value if all values passed are truthy.
In Clojure only false and nil are regarded as logically false. Everything else is regarded as logically true.
In the other Lisps you mention, the empty list is regarded as logically false.
The and operator evaluates the arguments and 'shortcircuits' the result, i.e. as soon as one argument is false, it returns nil. Otherwise, it returns the last value.
The difference in behavior is that in Common Lisp, the empty list is the same thing as nil, which is the same as false, therefore, (and '() t) is the same as (and nil t) which returns nil.
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))