Why do I get NPE in the following code? - clojure

The following code executes as expected but gives a NullPointerException at the end. What am I doing wrong here?
(ns my-first-macro)
(defmacro exec-all [& commands]
(map (fn [c] `(println "Code: " '~c "\t=>\tResult: " ~c)) commands))
(exec-all
(cons 2 [4 5 6])
({:k 3 :m 8} :k)
(conj [4 5 \d] \e \f))
; Output:
; Clojure 1.2.0-master-SNAPSHOT
; Code: (cons 2 [4 5 6]) => Result: (2 4 5 6)
; Code: ({:k 3, :m 8} :k) => Result: 3
; Code: (conj [4 5 d] e f) => Result: [4 5 d e f]
; java.lang.NullPointerException (MyFirstMacro.clj:0)
; 1:1 user=> #<Namespace my-first-macro>
; 1:2 my-first-macro=>
(For properly syntax highlighted code, go here.)

Take a look at the expansion that is happening:
(macroexpand '(exec-all (cons 2 [4 5 6])))
=>
((clojure.core/println "Code: " (quote (cons 2 [4 5 6])) "\t=>\tResult: " (cons 2 [4 5 6])))
As you can see, there is an extra pair of parentheses around your expansion, which means that Clojure tries to execute the result of the println function, which is nil.
To fix this I'd suggest modifying the macro to include a "do" at the front, e.g.
(defmacro exec-all [& commands]
(cons 'do (map (fn [c] `(println "Code: " '~c "\t=>\tResult: " ~c)) commands)))

Since the OP asked for other possible ways of writing this macro (see comments on the accepted answer), here goes:
(defmacro exec-all [& commands]
`(doseq [c# ~(vec (map (fn [c]
`(fn [] (println "Code: " '~c "=> Result: " ~c)))
commands))]
(c#)))
This expands to something like
(doseq [c [(fn []
(println "Code: " '(conj [2 3 4] 5)
"=> Result: " (conj [2 3 4] 5)))
(fn []
(println "Code: " '(+ 1 2)
"=> Result: " (+ 1 2)))]]
(c))
Note that the fn forms whose values will be bound to c are collected in a vector at macro-expansion time.
Needless to say, the original version is simpler, thus I think (do ...) is the perfect fix. :-)
Example interaction:
user=> (exec-all (conj [2 3 4] 5) (+ 1 2))
Code: (conj [2 3 4] 5) => Result: [2 3 4 5]
Code: (+ 1 2) => Result: 3
nil

Related

How do I get Clojure maro to output the original code without substitutions?

There is macros. This macro is convenient because it allows you
to see the result of executing the Clojure script.
But often it gives out a result that does not suit me.
I use Babashka for running scripts.
(defn symbol-several
"returns a symbol with the concatenation of the str values of the args"
[& x]
(symbol (apply str x)))
(defmacro ! [& forms]
(cons
`symbol-several
(for [form forms]
`(str '~form " ;-> " ~form "\n"))))
,that outputs:
c:\clj>bb "~#.clj"
(do (def v [3 4]) (def l (quote (1 2))) (clojure.core/sequence (clojure.core/seq (clojure.core/concat (clojure.core/list 0) l v)))) ;-> (0 1 2 3 4)
The ~#.clj file contains the macro "!" and the code:
"(! (do (def v [3 4]) (def l '(1 2)) `(0 ~#l ~#v)))"
How to rewrite a macro so that it outputs the original code, i.e. something like this:
(do (def v [3 4]) (def l '(1 2)) `(0 ~#l ~#v))) ;-> (0 1 2 3 4)
Also, instead of the result (list), the macro outputs LazySeq:
c:\clj>bb map.clj
(apply map vector [[1 2] [3 4]]) ;-> clojure.lang.LazySeq#8041
I use Babashka (bb.exe) for running script.
The map.clj file contains the macro "!" and the code:
(apply map vector [[1 2] [3 4]])
Using pr-str helps printing Clojure data structures properly.
(defn symbol-several
"returns a symbol with the concatenation of the str values of the args"
[& x]
(symbol (apply str x)))
(defmacro ! [& forms]
`(symbol-several
~#(for [form forms]
`(str '~form " ;-> " (pr-str ~form) "\n"))))
(! (apply map vector [[1 2] [3 4]]))
;; => (apply map vector [[1 2] [3 4]]) ;-> ([1 3] [2 4])
Also see https://clojuredocs.org/clojure.core/pr-str

Clojure: I am trying to use 'some' instead of 'doseq' but I am not really sure how to use it

How to replace the "doseq" with "some" in this scenario. I am new to clojure.
(def handle (atom ()))
;; #'user/players
;; conjoin a keyword into that list
(swap! handlers conj [:report "handles"])
;;=> ([:report "handles"])
;; conjoin a second keyword into the list
(swap! handlers conj [:demo "handles2"])
;;=> ([:demo "handles2"] [:report "handle"])
(doseq [[a b] #handlers] (println a "--" b))
;;=> :demo -- handles2
;;=> :report -- handles
The Clojure docs for doseq and some are loaded with examples that can help you figure out what to use and how to use it.
There are several things I don't know about your situation, but maybe I can help with these examples.
some
Detects if something exists based on a condition. Returns the result of the predicate, if the predicate returns truthy.
Takes a predicate and a collection
Predicate examples:
#(= 2 %) ; Equals 2
(fn [val] (= val "user3438838")) ; equals your username
Collection examples:
[1 2 3 4 5 6 7 8]
["user3438838" "programs" "in" "Clojure"]
Let's evaluate the combinations of these:
(some #(= 2 %) [1 2 3 4 5 6 7 8]) ; => true
(some #(= 2 %) ["user3438838" "programs" "in" "Clojure"]) ; => nil
(some (fn [val] (= val "user3438838")) [1 2 3 4 5 6 7 8]) ; => nil
(some (fn [val] (= val "user3438838")) ["user3438838" "programs" "in" "Clojure"]) => true
doseq
Implement an expression for all elements of a sequence, for side effects. This is the first function I looked for when coming from JS, but it's usually not the right thing (it doesn't take advantage of lazily evaluating, decreasing performance). Generally want to apply a recursive expression, like loop with recur, but doseq may make sense here.
We'll take the same approach as with some
doseq takes (a) sequence(s) and and expression that ostensibly uses each element of the sequence.
Sequence examples:
[x ["user3438838" "programs" "in" "Clojure"]]
[x [1 2 3 4 5 6 7 8]]
; Note: Can use multiple [x (range 10) y (range 10 20)]
Body expression examples:
(println x)
(println (str "The number/word is: " x))
And now we'll combine these:
(doseq [x ["user3438838" "programs" "in" "Clojure"]] (println x)) ; Prints "user3438838\nprograms\nin\nClojure"
(doseq [x ["user3438838" "programs" "in" "Clojure"]] (println (str "The number/word is: " x))) ; Prints "The word is: user3438838 ..."
(doseq [x [1 2 3 4 5 6 7 8]] (println x)) ; Prints "1\n2\n3\n4\n5\n6\n7\n8
(doseq [x [1 2 3 4 5 6 7 8]] (println (str "The number/word is: " x))) ; Prints "The number/word is: 1 ..."
Hope this helps you understand the two.
And if you're new, I think the go-to book for learning Clojure is Daniel Higginbotham's (2015) Clojure for the Brave and True where he describes some (and not doseq b/c you generally want to use lazily/recursively evaluated expressions).

Clojure; select all nth element from list of lists with unequal size, for n = 1, 2,

I'd like to have a function, such that,
(f '([1 4 7] [2 5 9] [3 6]))
would give
([1 2 3] [4 5 6] [7 9])
I tried
(apply map vector '([1 4 7] [2 5 9] [3 6]))
would only produce:
([1 2 3] [4 5 6])
I find it hard to describe my requirements that it's difficult for me to search for a ready solution.
Please help me either to improve my description, or pointer to a solution.
Thanks in advance!
I'd solve a more general problem which means you might reuse that function in the future. I'd change map so that it keeps going past the smallest map.
(defn map-all
"Like map but if given multiple collections will call the function f
with as many arguments as there are elements still left."
([f] (map f))
([f coll] (map f coll))
([f c1 & colls]
(let [step (fn step [cs]
(lazy-seq
(let [ss (keep seq cs)]
(when (seq ss)
(cons (map first ss)
(step (map rest ss)))))))]
(map #(apply f %) (step (conj colls c1))))))
(apply map-all vector '([1 4 7] [2 5 9] [3 6]))
(apply map-all vector '([1 false 7] [nil 5 9] [3 6] [8]))
Note, that as opposed to many other solutions, this one works fine even if any of the sequences contain nil or false.
or this way with loop/recur:
user> (defn transpose-all-2 [colls]
(loop [colls colls res []]
(if-let [colls (seq (filter seq colls))]
(recur (doall (map next colls))
(conj res (mapv first colls)))
res)))
#'user/transpose-all-2
user> (transpose-all-2 x)
[[1 2 3] [4 5 6] [7 9]]
user> (transpose-all-2 '((0 1 2 3) (4 5 6 7) (8 9)))
[[0 4 8] [1 5 9] [2 6] [3 7]]
If you know the maximum length of the vectors ahead of time, you could define
(defn tx [colls]
(lazy-seq
(cons (filterv identity (map first colls))
(tx (map rest colls)))))
then
(take 3 (tx '([1 4 7] [2 5 9] [3 6])))
A simple solution is
(defn transpose-all
[colls]
(lazy-seq
(let [ss (keep seq colls)]
(when (seq ss)
(cons (map first ss) (transpose-all (map rest ss)))))))
For example,
(transpose-all '([1 4 7] [2 5 9] [3 6] [11 12 13 14]))
;((1 2 3 11) (4 5 6 12) (7 9 13) (14))
Here is my own attempt:
(defn f [l]
(let [max-count (apply max (map count l))
l-patched (map (fn [e] (if (< (count e) max-count)
(concat e (take (- max-count (count e)) (repeat nil)))
e)) l)]
(map (fn [x] (filter identity x)) (apply map vector l-patched))
))
Another simple solution:
(->> jagged-list
(map #(concat % (repeat nil)))
(apply map vector)
(take-while (partial some identity)))
A jagged-list like this
'([1 4 7 ]
[2 5 9 ]
[3 6 ]
[11 12 13 14])
will produce:
'([1 2 3 11]
[4 5 6 12]
[7 9 nil 13]
[nil nil nil 14])
Here is another go that doesn't require you to know the vector length in advance:
(defn padzip [& [colls]]
(loop [acc [] colls colls]
(if (every? empty? colls) acc
(recur (conj acc (filterv some?
(map first colls))) (map rest colls)))))

clojure: pop and push

I'm looking for a sequential data structure which is perfect for the following operation. The lenght of the list remains constant, it will never be longer or shorter than a fixed length.
Omit the first item and add x to the end.
(0 1 2 3 4 5 6 7 8 9)
(pop-and-push "10")
(1 2 3 4 5 6 7 8 9 10)
There is only one other reading-operation that has to be done equally often:
(last coll)
pop-and-push could be implemented like this:
(defn pop-and-push [coll x]
(concat (pop coll) ["x"]))
(unfortunately this does not work with sequences produced by e.g. range, it just pops when the sequence declared by the literals '(..) is passed.)
but is this optimal?
The main issue here (once we change "x" to x) is that concat returns a lazy-seq, and lazy-seqs are invalid args to pop.
user=> (defn pop-and-push [coll x] (concat (pop coll) [x]))
#'user/pop-and-push
user=> (pop-and-push [1 2 3] 4)
(1 2 4)
user=> (pop-and-push *1 5)
ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IPersistentStack clojure.lang.RT.pop (RT.java:730)
My naive preference would be to use a vector. This function is easy to implement with subvec.
user=> (defn pop-and-push [v x] (conj (subvec (vec v) 1) x))
#'user/pop-and-push
user=> (pop-and-push [1 2 3] 4)
[2 3 4]
user=> (pop-and-push *1 5)
[3 4 5]
as you can see, this version can actually operate on its own return value
As suggested in the comments, PersistentQueue is made for this situation:
user=> (defn pop-and-push [v x] (conj (pop v) x))
#'user/pop-and-push
user=> (pop-and-push (into clojure.lang.PersistentQueue/EMPTY [1 2 3]) 4)
#object[clojure.lang.PersistentQueue 0x50313382 "clojure.lang.PersistentQueue#7c42"]
user=> (into [] *1)
[2 3 4]
user=> (pop-and-push *2 5)
#object[clojure.lang.PersistentQueue 0x4bd31064 "clojure.lang.PersistentQueue#8023"]
user=> (into [] *1)
[3 4 5]
The PersistentQueue data structure, though less convenient to use in some ways, is actually optimized for this usage.

How to write a Clojure function that returns a list of adjacent pairs?

I'm trying to write a function adjacents that returns a vector of a sequence's adjacent pairs. So (adjacents [1 2 3]) would return [[1 2] [2 3]].
(defn adjacents [s]
(loop [[a b :as remaining] s
acc []]
(if (empty? b)
acc
(recur (rest remaining) (conj acc (vector a b))))))
My current implementation works for sequences of strings but with integers or characters the REPL outputs this error:
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:494)
The problem here is in the first evaluation loop of (adjacents [1 2 3]), a is bound to 1 and b to 2. Then you ask if b is empty?. But empty? works on sequences and b is not a sequence, it is a Long, namely 2. The predicate you could use for this case here is nil?:
user=> (defn adjacents [s]
#_=> (loop [[a b :as remaining] s acc []]
#_=> (if (nil? b)
#_=> acc
#_=> (recur (rest remaining) (conj acc (vector a b))))))
#'user/adjacents
user=> (adjacents [1 2 3 4 5])
[[1 2] [2 3] [3 4] [4 5]]
But, as #amalloy points out, this may fail to give the desired result if you have legitimate nils in your data:
user=> (adjacents [1 2 nil 4 5])
[[1 2]]
See his comment for suggested implementation using lists.
Note that Clojure's partition can be used to do this work without the perils of defining your own:
user=> (partition 2 1 [1 2 3 4 5])
((1 2) (2 3) (3 4) (4 5))
user=> (partition 2 1 [1 2 nil 4 5])
((1 2) (2 nil) (nil 4) (4 5))
Here is my short answer. Everything becomes a vector, but it works for all sequences.
(defn adjacent-pairs [s]
{:pre [(sequential? s)]}
(map vector (butlast s) (rest s)))
Testing:
user=> (defn adjacent-pairs [s] (map vector (butlast s) (rest s)))
#'user/adjacent-pairs
user=> (adjacent-pairs '(1 2 3 4 5 6))
([1 2] [2 3] [3 4] [4 5] [5 6])
user=> (adjacent-pairs [1 2 3 4 5 6])
([1 2] [2 3] [3 4] [4 5] [5 6])
user=>
This answer is probably less efficient than the one using partition above, however.