How to force evaluate? - clojure

After playing a while with quote/unquote, I wanted to do a trick, but it didn't want to be done. Here's what I did and what come out :
user=> (let [x '#(inc 1)] `(1 ~x))
(1 (fn* [] (inc 1)))
But what I wanted was :
(1 2)
Can you help me do that ? :)
And also explain what "part" of Clojure you are using...

You can use eval:
user=> (let [x `(inc 1)]
(eval `(list 1 ~x)))
(1 2)
Or more conventionally:
user=> (defmacro foo [x]
`(list 1 ~x))
#'user/foo
user=> (foo (inc 1))
(1 2)

This will work like you want it to:
user> (let [x (#(inc 1))] `(1 ~x))
;=> (1 2)

Related

fn and let inside clojure macro

I'm running into some limitations of Clojure macros. I wonder how to optimize the following code?
(defmacro ssplit-7-inefficient [x]
(let [t 7]
;; Duplicated computation here!
`(do [(first (split-with #(not (= '~t %)) '~x))
(drop 1 (second (split-with #(not (= '~t %)) '~x)))])))
(ssplit-7-inefficient (foo 7 bar baz))
;; Returns: [(foo) (bar baz)]
Here are some approaches that don't work:
(defmacro ssplit-7-fails [x]
(let [t 7]
`(do ((fn [[a b]] [a (drop 1 b)]) (split-with #(not (= '~t %)) '~x)))))
(ssplit-7-fails (foo 7 bar baz))
;; Error: Call to clojure.core/fn did not conform to spec.
(defmacro ssplit-7-fails-again [x]
(let [t 7]
`(do
(let [data (split-with #(not (= '~t %)) '~x)]
((fn [[a b]] [a (drop 1 b)]) data)))))
(ssplit-7-fails-again (foo 7 bar baz))
;; Error: Call to clojure.core/let did not conform to spec.
Note that split-with splits only once. You can use some destructuring to get what you want:
(defmacro split-by-7 [arg]
`((fn [[x# [_# & z#]]] [x# z#]) (split-with (complement #{7}) '~arg)))
(split-by-7 (foo 7 bar baz))
=> [(foo) (bar baz)]
In other use cases, partition-by can be also useful:
(defmacro split-by-7 [arg]
`(->> (partition-by #{7} '~arg)
(remove #{[7]})))
(split-by-7 (foo 7 bar baz))
=> ((foo) (bar baz))
It is not so easy to reason about macros in Clojure - (in my view macroexpand-1 alienates the code a lot - in contrast to Common Lisp's macroexpand-1 ...).
My way was first to build a helper function.
(defn %split-7 [x]
(let [y 7]
(let [[a b] (split-with #(not= y %) x)]
[a (drop 1 b)])))
This function uses destructuring so that the split-with is "efficient".
It does nearly exactly what the macro should do. Just that one has to quote
the argument - so that it works.
(%split-7 '(a 7 b c))
;;=> [(a) (b c)]
From this step to the macro is not difficult.
The macro should just automatically quote the argument when inserting into the helper function's call.
(defmacro split-7 [x]
`(%split-7 '~x))
So that we can call:
(split-7 (a 7 b c))
;; => [(a) (b c)]
Using this trick, even generalize the function to:
(defn %split-by [x y]able like this
(let [[a b] (split-with #(not= y %) x)]
[a (drop 1 b)]))
(defmacro split-by [x y]
`(%split-by '~x ~y))
(split-by (a 7 b c) 7)
;; => [(a) (b c)]
(split-by (a 7 b c 9 d e) 9)
;; => [(a 7 b c) (d e)]
The use of (helper) functions in the macro body - and even other macros - or recursive functions or recursive macros - macros which call other macros - shows how powerful lisp macros are. Because it shows that you can use the entirety of lisp when formulating/defining macros. Something what most language's macros usually aren't able to do.

How to get tails of sequence clojure

I have sequence in clojure of theem
(1 2 3 4)
how can I get all the tails of sequence like
((1 2 3 4) (2 3 4) (3 4) (4) ())
Another way to get all tails is by using the reductions function.
user=> (def x '(1 2 3 4))
#'user/x
user=> (reductions (fn [s _] (rest s)) x x)
((1 2 3 4) (2 3 4) (3 4) (4) ())
user=>
If you want to do this with higher-level functions, I think iterate would work well here:
(defn tails [xs]
(concat (take-while seq (iterate rest xs)) '(()))
However, I think in this case it would be cleaner to just write it with lazy-seq:
(defn tails [xs]
(if-not (seq xs) '(())
(cons xs (lazy-seq (tails (rest xs))))))
Here is one way.
user=> (def x [1 2 3 4])
#'user/x
user=> (map #(drop % x) (range (inc (count x))))
((1 2 3 4) (2 3 4) (3 4) (4) ())
One way you can do that is by
(defn tails [coll]
(take (inc (count coll)) (iterate rest coll)))
(defn tails
[s]
(cons s (if-some [r (next s)]
(lazy-seq (tails r))
'(()))))
Yippee! Another one:
(defn tails [coll]
(if-let [s (seq coll)]
(cons coll (lazy-seq (tails (rest coll))))
'(())))
This is really just what reductions does under the hood. The best answer, by the way, is ez121sl's.

Trouble with clojure quote-paren `( ... ) macro

For practice, I've defined
(defmacro quote-paren
"body -> `(body)"
[& body]
`(~#body))
which has the expected transformation (quote-paren body) => ``(body)`. It seems to satisfy a few basic tests:
user=> (macroexpand-1 `(quote-paren 3 4 5))
(3 4 5)
user=> (macroexpand-1 `(quote-paren println "hi"))
(clojure.core/println "hi")
user=> (macroexpand-1 `(quote-paren (println "hi")))
((clojure.core/println "hi"))
However, I've been testing it with this do-while macro (modified from here):
(defmacro do-while
[test & body]
(quote-paren loop []
~#body
(when ~test
(recur))))
(def y 4)
(do-while (> y 0)
(def y (dec y)))
But the result is
IllegalStateException Attempting to call unbound fn: #'clojure.core/unquote-splicing clojure.lang.Var$Unbound.throwArity (Var.java:43)
I don't understand this, because from what I can see the `quote-paren' macro works fine (with ~#body plugged in):
user=> (macroexpand-1
`(quote-paren loop []
(def y (dec y))
(when ~test
(recur))))
(clojure.core/loop [] (def user/y (clojure.core/dec user/y)) (clojure.core/when #<core$test clojure.core$test#1f07f672> (recur)))
But trying to macroexpand do-while causes an "unbound fn". Is there something subtle I'm missing?
missing the syntax-quote before quote-paren
user> (defmacro do-while
[test & body]
`(quote-paren loop []
~#body
(when ~test
(recur))))
#'user/do-while
which then expands properly:
user> (macroexpand '(do-while (> y 0)
(def y (dec y))))
(loop* [] (def y (dec y)) (clojure.core/when (> y 0) (recur)))
and seems to work:
user> (def y 4)
#'user/y
user> (do-while (> y 0)
(def y (dec y)))
nil
user>

Strange error when using atoms inside deftype

I have the following code, defining a type that has an atom in there.
(defprotocol IDeck
(vec-* [dk] "Output to a persistent vector")
(count-* [dk] "Number of elements in the deck")
(conj1-* [dk & es] "Adding multiple elements to the deck"))
(deftype ADeck [#^clojure.lang.Atom val]
IDeck
(vec-* [dk] (->> (.val dk) deref (map deref) vec))
(count-* [dk] (-> (.val dk) deref count))
(conj1-* [dk & es]
(try
(loop [esi es]
(let [e (first esi)]
(cond
(nil? e) dk
:else
(do
(swap! (.val dk) #(conj % (atom e)))
(recur (rest esi))))))
(catch Throwable t (println t)))))
(defn new-*adeck
([] (ADeck. (atom [])))
([v] (ADeck. (atom (vec (map atom v))))))
(defn conj2-* [dk & es]
(try
(loop [esi es]
(let [e (first esi)]
(cond
(nil? e) dk
:else
(do
(swap! (.val dk) #(conj % (atom e)))
(recur (rest esi))))))
(catch Throwable t (println t))))
;; Usage
(def a (new-*adeck [1 2 3 4]))
(count-* a)
;=> 4
(vec-* a)
;=> [1 2 3 4]
(conj1-* a 1 2) ;; The deftype case
;=> IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long
(vec-* a)
;=> [1 2 3 4]
(conj2-* a 1 2) ;; The defn case
(vec-* a)
;=> [1 2 3 4 1 2]
Even though the two conj-* methods are exactly the same, except that one is in a deftype and the other is a normal defn, the first gives an error while the second succeeds. Why is this?
This is because protocols doesn't support variable number of arguments.
What you can do is make:
(conj1-* [dk & es] "Adding multiple elements to the deck"))
into
(conj1-* [dk es] "Adding multiple elements to the deck"))
such that the es param will be vector and called like:
(conj1-* a [1 2])

unexpected output for map inside of do

Why doesn't this produce the output I expect?
(defn test-fn []
(do
(println "start")
(map #(println (+ % 1)) '(1 2 3))
(println "done")))
It outputs
start
done
Whereas I would expect
start
2 3 4
done
map is lazy, and do does not force it. If you want to force the evaluation of a lazy sequence, use doall or dorun.
(defn test-fn []
(do
(println "start")
(dorun (map #(println (+ % 1)) '(1 2 3)))
(println "done")))