Using a loop inside a macro - clojure

Consider this minimal example
(defmacro foo []
`(list ,#(for [i [1 2 3]] (+ 1 i))))
I expect (foo) to expand to (list 2 3 4)
But instead, I get a bunch of indecipherable errors when I try (macroexpand-1 (foo)
Syntax error macroexpanding clojure.core/let at (*cider-repl <filepath>:localhost:43203(clj)*:366:22).
test/i - failed: simple-symbol? at: [:bindings :form :local-symbol] spec: :clojure.core.specs.alpha/local-name
test/i - failed: vector? at: [:bindings :form :seq-destructure] spec: :clojure.core.specs.alpha/seq-binding-form
test/i - failed: map? at: [:bindings :form :map-destructure] spec: :clojure.core.specs.alpha/map-bindings
test/i - failed: map? at: [:bindings :form :map-destructure] spec: :clojure.core.specs.alpha/map-special-binding
What's going wrong? Can't I use for loops inside my macro definitions?

,# should be ~#.
user=> (defmacro foo []
`(list ~#(for [i [1 2 3]] (+ 1 i))))
#'user/foo
user=> (macroexpand-1 '(foo))
(clojure.core/list 2 3 4)
user=> (foo)
(2 3 4)

Related

Why are these Clojure lists different?

I'm running through some of the 4Clojure problems and hit some weird behavior with some of my code. Upon further investigation it seems the culprit was using the quote macro vs list function. Why does this matter in the code below, and why does it produce the incorrect result?
user=> (= (class '(/ 1 2)) (class (list / 1 2)))
true
user=> (def a '(/ 1 2))
#'user/a
user=> (def b (list / 1 2))
#'user/b
user=> (class a)
clojure.lang.PersistentList
user=> (class b)
clojure.lang.PersistentList
user=> (apply (first a) (rest a))
2
user=> (apply (first b) (rest b))
1/2
user=> (class (first a))
clojure.lang.Symbol
user=> (class (first b))
clojure.core$_SLASH_
'(/ 1 2)
is analogous to:
(list '/ 1 2)
When you don't quote /, you get its value, which is the built-in division function, rather than the symbol.
Unfortunately, you have used the symbol object as function in expression (apply (first a) (rest a)). The symbol object looks for the value of itself as a key in a map:
('/ {'+ :plus '/ :slash '- :minus} :not-found)
=> :slash
('/ {'+ :plus '$ :dollar '- :minus} :not-found)
=> :not-found
('/ 1 :not-found)
=> :not-found
('/ 1 2)
=> 2

Clojure length of sequence

I could have sworn I had alength working previously, but I don't quite know what I am doing wrong right now:
user=> (alength '(1 2 3))
IllegalArgumentException No matching method found: alength clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:79)
user=> (alength [1 2 3])
IllegalArgumentException No matching method found: alength clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:79)
user=> (doc alength)
-------------------------
clojure.core/alength
([array])
Returns the length of the Java array. Works on arrays of all
types.
nil
What should I be doing to get the length of a list/array in Clojure?
Try using count:
(count '(1 2 3))
=> 3
(count [1 2 3])
=> 3
As the docstring says, alength works on Java™ arrays, such as a String[] or Integer[], which is definitely an incompatible type with Clojure lists or vectors, for which you want to use count:
user=> (def x '(1 2 3))
#'user/x
user=> (def xa (to-array x))
#'user/xa
user=> (class x)
clojure.lang.PersistentList
user=> (class xa)
[Ljava.lang.Object;
user=> (alength xa)
3
user=> (alength x)
java.lang.IllegalArgumentException: No matching method found: alength (NO_SOURCE_FILE:0)
user=> (count x)
3
[Ljava.lang.Object; is the weird way toString is defined to output for native Object arrays.
It should be count.
user=> (count '(1 2 3))
3
This may be overkill, but you could imitate Common LISP's length function like this:
(def length
(fn [lst]
(loop [i lst cnt 0]
(cond (empty? i) cnt
:t (recur (rest i)(inc cnt))))))
You can do that using the recursive way:
(defn length
[list]
(if (empty? list) 0
(+ 1 (length (rest list)))))
Hope it helps!

Add items in a list/sequence in Clojure

There has to be a simple way to do this, and I am obviously missing it :|
How do you add the items in a list\sequence (not clear on the difference) in clojure?
I've tried the following:
Clojure> (add [1 2 3])
java.lang.RuntimeException: Unable to resolve symbol: add in this context
Clojure> (+ [1 2 3])
java.lang.ClassCastException: Cannot cast clojure.lang.PersistentVector to java.lang.Number
Clojure> (apply merge-with + [1 2 3])
java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long
Clojure> (add-items [1 2 3])
java.lang.RuntimeException: Unable to resolve symbol: add-items in this context
(+ 1 2 3)
...will do it. #Nathan Hughes's solution:
(apply + [1 2 3])
...works if you have a reference to the sequence rather than defining it inline, e.g.:
(def s [1 2 3])
; (+ s) CastClassException
(apply + s) ; 6
As #4e6 notes, reduce also works:
(reduce + s) ; 6
Which is better? Opinions vary.

Clojure: Difference between a list and a function that returns a list

I'm a Clojure newbie. I'm trying to understand why the second form doesn't work:
First form:
user=>(def nums(range 3))
(0 1 2)
user=>(map #(list %1) nums)
((0) (1) (2))
Second form:
user=> (map #(list %1) (0 1 2))
java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn
(NO_SOURCE_FILE:0)
The problem is the expression (0 1 2), which is interpreted as 0 applied to 1 and 2; that's impossible because 0 isn't a function.
(map #(list %1) '(0 1 2))
works as intended, though.
Because (0 1 2) means call function 0 with args 1 and 2, but 0 is not a function. So you need to make is a list rather than function application using quote or list function i.e '(0 1 2)
OR (list 0 1 2)
larsmans and Ankur have it. I realize this is a trivial example, but it would probably be more idiomatic to use a vector rather than a list:
(map #(list %1) [0 1 2])
You can also use % instead of %1 when there's only one arg passed to the anonymous function.
(map #(list %) [0 1 2])
user=> (map list (range 3))
((0) (1) (2))
user=> (map list '(0 1 2))
((0) (1) (2))
user=> (map list [0 1 2])
((0) (1) (2))

Clojure's # lambda marco is not always the same as (fn)?

user> (map (fn [k] [k]) [1 2 3])
([1] [2] [3])
user> (map #([%1]) [1 2 3])
.... Error..
Why is the second example an error?
The #(<expr>) reader macro wraps the <expr> in an extra set of parenthesis, so #([%1]) expands to something equivalent to (fn [%1] ([%1])) and not (fn [%1] [%1]). So you are right. They are not entirely equivalent.
You can try the following in the REPL which will reveal the exact expansion:
user=> '#([%1])
(fn* [p1__862#] ([p1__862#]))
user=> '#(inc %1)
(fn* [p1__865#] (inc p1__865#))