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
Related
I am trying to get a list to evaluate to a true/false against a particular number. When I define the function, clojure defines it fine. But it is not doing what I want to do. Just learning clojure... so I am not very comfortable with the syntax yet... apologies if this is a noob question.
Ideally it would take in a list like (list 9 0 3) and evaluate it to (list true false true)
(defn myfunc [lst](map (> x 1) lst))
Here is the correct syntax:
(defn greater-than-one?
[x]
(< 1 x))
and then use it:
(mapv greater-than-one? (list 9 0 3)) => [true false true]
In your original format, you could also solve it like:
(defn myfunc [lst]
(map #(> % 1) lst))
and use it:
(myfunc (list 9 0 3)) => (true false true)
You may find this template project helpful in getting started. Please be sure to see the list of documentation also.
I came across this macro definition for unless from the brave and true book
(defmacro unless
"Inverted 'if'"
[test & branches]
(conj (reverse branches) test 'if))
I believe the rest param is a sequence, and the conj returns a sequence, so this entire macro returns a sequence. I thought you needed to return a list for the return to be evaluated properly
On further investigation, why does (eval (sequence [+ 1 4 4])) do the same thing as (eval (list 1 4 4)). Where does it say that sequences are evaluated like lists? I don't see that in the docs. –
You have just proven that a list, a seq, and a sequence are all treated as function call sites by the Clojure compiler. That is your answer.
=> (def xxx [+ 2 3]) ; a function and 2 integers in a vector
=> (eval xxx) ; a vector doesn't work
[#object[clojure.core$_PLUS_ 0x375dfecb "clojure.core$_PLUS_#375dfecb"] 2 3]
=> (eval (seq xxx)) ; a seq works
5
=> (eval (sequence xxx)) ; a sequence works
5
=> (eval (apply list xxx)) ; converts xxx to a list (+ 2 3) which works
5
When the Clojure docs are ambiguous or are missing some detail, a small experiment like the above will answer your question.
If the answer applies to a specific area of the Clojure website, function docstring, or clojuredocs.org or clojure-doc.org, you may consider submitting a pull-request to update & improve the docs.
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.
Say X is a data expression in Scheme. I am wondering if there is a way to test if X is a list, and if so, my machine will output #t, otherwise it will output #f.
You can use the function list?:
(list? 42)
=> #f
(list? '(1 2 3))
=> #t
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.