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

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#))

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 loop with count

I am fairly new to Clojure and would help help with some code. I have a function which takes a vector and i would like to loop through the vector and get the value at an index 'i' and the value of 'i' itself. 'i' is the value which is incremented in the loop.
I have checked 'for' at the clojure docs at for and wrote the following code.
(for [i some-vector]
(print (get-intersec i (.length some-vector) loop-count)))
The loop-count variable is supposed to be the loop count.
I have also checked loop but it does not seem like a feasible solution. Can someone help me with a clojure function i can use or help me write a macro or function that can do that.
Thank you.
Ps: To solve my problem, i use my own counter but would like a better solution.
First, keep in mind that for is for list comprehension, that is, creating new sequences. For looping through a sequence for some side effect, like printing, you probably want to use doseq.
To include a numeric count with each element as you loop through, you can use map-indexed:
(def xs [:a :b :c :d])
(doseq [[n elem] (map-indexed #(vector %1 %2) xs)]
(println n "->" elem))
Output:
0 -> :a
1 -> :b
2 -> :c
3 -> :d
If you find yourself doing this a lot, like I did, you can create a macro:
(defmacro doseq-indexed [[[item idx] coll] & forms]
`(doseq [[~idx ~item] (map-indexed #(vector %1 %2) ~coll)]
~#forms))
And use it like this:
> (doseq-indexed [[n elem] xs] (println n "->" elem))
0 -> :a
1 -> :b
2 -> :c
3 -> :d
Don't forget dotimes for simple stuff like this:
(let [data [:a :b :c :d]]
(dotimes [i (count data)]
(println i " -> " (data i))
; or (nth data i)
; or (get data i)
))
with result
0 -> :a
1 -> :b
2 -> :c
3 -> :d
Using loop/recur would look like this:
(let [data [:a :b :c :d]]
(loop [i 0
items data]
(let [curr (first items)]
(when curr
(println i "->" curr)
(recur (inc i) (rest items))))))
Update:
If you need this a lot, I already wrote a function that will add the index value to the beginning of each entry in a sequence:
(ns tst.demo.core
(:use tupelo.test)
(:require [tupelo.core :as t]) )
(dotest
(let [data [:a :b :c :d]]
(t/spy-pretty :indexed-data
(t/indexed data))))
with result
:indexed-data =>
([0 :a]
[1 :b]
[2 :c]
[3 :d])
The general signature is:
(indexed & colls)
Given one or more collections, returns a sequence of indexed tuples
from the collections like:
(indexed xs ys zs) -> [ [0 x0 y0 z0]
[1 x1 y1 z1]
[2 x2 y2 z2]
... ]
If your not set on using for, you could use map-indexed e.g.
(map-indexed (fn [i v]
(get-intersect v (.length some-vector) i))
some-vector))
I don't know what get-intersect is and assume .length is java interop? Anyway, map-indexed expects a function of 2 arguments, the 1st is the index and the second is the value.

Why does this clojure macro need `'~?

(Apologies if this is a duplicate of another question, my search for all those fancy special characters didn't yield anything.)
I'm reading Mastering Clojure Macros and have trouble understanding the following example:
(defmacro inspect-caller-locals []
(->> (keys &env)
(map (fn [k] [`'~k k]))
(into {})))
=> #'user/inspect-caller-locals
(let [foo "bar" baz "quux"]
(inspect-caller-locals))
=> {foo "bar", baz "quux"}
What is the difference between the following and the much simpler 'k?
`'~k
As far as I understand, the innermost unquote ~ should simply reverts the effect of the outermost syntax-quote `, but a short experiment reveals that there's more to it:
(defmacro inspect-caller-locals-simple []
(->> (keys &env)
(map (fn [k] ['k k]))
(into {})))
=> #'user/inspect-caller-locals-simple
(let [foo "bar" baz "quux"]
(inspect-caller-locals-simple))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: k in this context, compiling:(/tmp/form-init4400591386630133028.clj:2:3)
Unfortunately, my usual investigation approach doesn't apply here:
(macroexpand '(let [foo "bar" baz "quux"]
(inspect-caller-locals)))
=> (let* [foo "bar" baz "quux"] (inspect-caller-locals))
(let [foo "bar" baz "quux"]
(macroexpand '(inspect-caller-locals)))
=> {}
What am I missing here?
Let's first establish what the k inside the macro is:
(defmacro inspect-caller-locals []
(mapv (fn [k]
(println (class k)))
(keys &env))
nil)
(let [x 1]
(inspect-caller-locals))
;; Prints:
;; clojure.lang.Symbol
So you each k inside the function is a symbol. If you return a symbol from a macro (ie generate code from it), clojure will lookup the value that it refers to and print it. For instance you could do this:
(defmacro inspect-caller-locals []
(mapv (fn [k]
[(quote x) k]) ;; not the "hard coded" x
(keys &env)))
(let [x 1]
(inspect-caller-locals))
;; Prints:
;; [[1 1]]
What you want however is the actual symbol. The problem (as you noted) is that quote is a special form that DOES NOT EVALUTE whatever you pass it. Ie, the k will not obtain the function parameter but stay k which is not usually defined:
(defmacro inspect-caller-locals []
(mapv (fn [k]
[(quote k) k])
(keys &env)))
(let [x 1]
(inspect-caller-locals))
;; => Error
(let [k 1]
(inspect-caller-locals))
;; Prints:
;; [[1 1]]
You somehow need to evaluate what you pass into quote, this is not however possible since that isn't what quote does. Other functions, such as str don't have that problem:
(defmacro inspect-caller-locals []
(mapv (fn [k]
[(str k) k])
(keys &env)))
(let [x 1]
(inspect-caller-locals))
;; Prints:
;; [["x" 1]]
The trick is to go one level deeper and quote the quote itself so you can pass the symbol to it:
(defmacro inspect-caller-locals []
(mapv (fn [k]
[;; This will evaluate k first but then generate code that
;; wraps that symbol with a quote:
(list (quote quote) k)
;; Or equivalently and maybe easier to understand:
(list 'quote k)
k])
(keys &env)))
(let [x 1]
(inspect-caller-locals))
;; Prints:
;; [[x x 1]]
Or by using the reader that can do this for you:
(defmacro inspect-caller-locals []
(mapv (fn [k]
[`(quote ~k)
`'~k
k])
(keys &env)))
(let [x 1]
(inspect-caller-locals))
;; Prints:
;; [[x x 1]]
Because after all:
(read-string "`'~k")
=> (clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list k)))
(defmacro inspect-caller-locals []
(mapv (fn [k]
[(clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list k)))
k])
(keys &env)))
(let [x 1]
(inspect-caller-locals))
;; Prints:
;; [[x 1]]
Some alternative, and equivalent, ways of writing
`'~k
are:
`(quote ~k) ;; expands the ' reader macro to the quote special form
(list 'quote k) ;; avoids syntax quote entirely
You are pretty much right to think that
the innermost unquote ~ should simply reverts the effect of the outermost syntax-quote
The only thing missing from your description there is that you can't pull quote outside of a syntax-quoted expression, since quote is a special form and changes the meaning of what's inside. Otherwise,
'`~k
would be equivalent to 'k - and as you noticed, it's not!
I'll echo #amalloy's general advice, that trying syntax-quoted stuff in the REPL, outside of the context of macros/macroexpansion, is the best way to get your head around these things.
p.s. Also, I'll make a note that I need to fix this confusion by explaining better in a future book edition ;)

Idiom for transducing over an atom?

What is the idiomatic way to apply transducers to an atom's value?
This seems to do the job, but I'm unsure of correctness (and style ^^).
(let [xf1 (map inc)
xf2 (map #(+ % 2))
xf #(vec (eduction (comp xf2 xf1) %))
a (atom [1 2 3])]
(swap! a xf))
;=> [4 5 6]
(let [xf1 (map inc)
xf2 (map #(* % 2))
foo #(into [] (comp xf2 xf1) %)
a (atom [1 2 3])]
(swap! a foo))
;; => [3 5 7]
There are two things you need to take note.
comp in transducers works the opposite order as normal applications. That is, xf2 is applied prior to xf1. For each element, it is doubled then incremented.
eduction returns a sequence, so it's not the same type as your original value in the atom.

misunderstanding of variable arguments type

I am trying to solve a clojure problem where I implement my own comp function.
I have the following expression that works how I expect:
(reduce #(apply %2 [%1]) [1 2 3 4] [rest reverse])
This gives an output of
(4 3 2)
I have tried abstracting this into a function like this:
(((fn [& funcs]
(fn [& args]
(reduce #(apply %2 [%1]) args funcs)
)) rest reverse) [1 2 3 4])
But I get the following error when I run it:
CompilerException java.lang.ClassCastException: clojure.lang.ArraySeq
cannot be cast to java.lang.Number,
compiling:(/Users/paulcowan/projects/scratch/src/scratch/core.clj:1:1)
To me the only difference that I can see is how that funcs and args are different types than the vectors that I created in the first example.
Why does reduce and apply behave differently in the second example?
Simply:
(defn my-comp [& fns]
(fn [x] (reduce #(%2 %1) x fns)))
giving
((my-comp rest reverse) [1 2 3 4])
;(4 3 2)
As it should, my-comp returns an identity function for an empty argument list.
But it expects all functions, including the first applied,
to take a single argument.
To get round (2), adapt it as follows:
(defn my-comp [& fns]
(if (empty? fns)
identity
(let [[f & fs] fns]
(fn [& args] (reduce #(%2 %1) (apply f args) fs)))))
Apart from (1), this merely rephrases Mark's answer.
For fun ...
We could define my-comp in terms of the standard comp:
(defn my-comp [& fns] (apply comp (reverse fns)))
But it probably makes more sense the other way round, since comp has to reverse its argument list in general:
(defn comp [& fns] (apply my-comp (reverse fns)))
We could even define an argument reverser
(defn rev-args [f] (fn [& args] (apply f (reverse args))))
... which turns a function into one that does the same thing to a reversed argument list.
Then
(def comp (rev-args my-comp))
or vice-versa:
(def my-comp (rev-args comp))
First of all, I don't get any error messages (nor correct result):
user> (((fn [& funcs]
(fn [& args]
(reduce #(apply %2 [%1]) args funcs))) rest reverse) [1 2 3 4])
;; => ()
Difference between the two examples is that in the first one you pass value [1 2 3 4] into reduce, while in the second one you pass [[1 2 3 4]] (because args is meant to keep all arguments of the function as one vector.
This will work:
user> (((fn [& funcs]
(fn [args]
(reduce #(apply %2 [%1]) args funcs))) rest reverse) [1 2 3 4])
;; => (4 3 2)
However, to get a function for functional composition that will be able to take any number of arguments, you should write something like this:
user> (defn my-comp [& fncs]
(fn [& args]
(reduce #(%2 %1) ; you can omit apply here, as %2 is already function
; and %1 is always one value, as noisesmith noticed
(apply (first fncs) args)
(rest fncs))))
;; => #'user/my-comp
user> (def my-fnc (my-comp rest reverse))
;; => #'user/my-fnc
user> (my-fnc [1 2 3 4])
;; => (4 3 2)
It will work fine, because only first function should have ability to take many arguments, as others will be applied to value returned by previously called function.