1

I am pretty new with Clojure language.

While reading about Clojure functions, I find the example #([%]). So I try to use it as follows:

(def test1 #([%]))
(test1 5)

As a result, I get the following error:

ArityException Wrong number of args (0) passed to: PersistentVector  clojure.lang.AFn.throwArity (AFn.java:429)

which seems to be that it is trying to invoke the array I wanted to return.

After digging a while, I find a solution as follows:

(def test1 #(-> [%]))
(test1 5)

I would have some questions:

  1. Why doesn't the #([%]) work? What did I do with the expression #([x])?
  2. In the correct example I am using the thread-first macro. Based on its documentation, it is used to pass an argument to the next function, e.g. (-> x (+ 1)). In this case I do not even have a function to pass to; *what is the next function in this context? I can not realize why it solved my issue
fcracker79
  • 1,118
  • 13
  • 26
  • 1
    the canonical would be `#(vector x)`. The answer – leetwinski Jul 17 '20 at 07:21
  • thanks @leetwinski, I am using those functions just for studying purpose. The tutorial itself suggests to use the `vector` function. – fcracker79 Jul 17 '20 at 08:13
  • 1
    Your main question is covered very thoroughly at https://stackoverflow.com/questions/4921566/clojure-returning-a-vector-from-an-anonymous-function. I'm not closing this as a duplicate though, because the additional discussion of `->` is useful. – amalloy Jul 17 '20 at 09:27

2 Answers2

5

Question 1

The syntax #([%]) translates into: "Create a function that when called will evaluate the expression ([%]) with % being the first (and only) argument passed to the function". This expression has the syntax of a function call with [%] being the function to be called. You can see what goes on using a macroexpand:

(macroexpand '#([%]))
;; => (fn* [p1__6926#] ([p1__6926#]))

The class of persistent vectors in clojure is clojure.lang.PersistentVector. They implement the IFn interface for arity 1, so that you can treat the vector as a function mapping an index to an element. But they do not implement arity 0, which is what you are trying to call. In other words, your code does not work:

(def test1 #([%]))
(test1 5) ;; ERROR

However, if you would pass the argument 0 to your function [%], you would get back the element:

(def test1 #([%] 0))
(test1 5)
;; => 5

Do you see what happens? However, for the thing you are trying to do, there is a better way: The [a b c] syntax is just sugar for calling (vector a b c). So to get something that works, you can just do

(def test1 vector)
(test1 5)
;; => [5]

Question 2

The thread-first macros has the syntax of (-> x f0 f1 f2 ...) where x is the initial value and f0, f1 and so on are function calls with their first argument left out to be replaced by the value that is being piped through. Again we can use macroexpand to understand:

(macroexpand '(-> x f0 f1 f2))
;; => (f2 (f1 (f0 x)))

But in your case, the function calls are left out. To analyze your second example, we need to use clojure.walk/macroexpand-all for a full expansion, because we have nested macros:

(clojure.walk/macroexpand-all '#(-> [%]))
;; => (fn* [p1__6995#] [p1__6995#])

although, we can also look at it one step at a time:

(macroexpand '#(-> [%]))
;; => (fn* [p1__7000#] (-> [p1__7000#]))

(macroexpand '(-> [p1__7000#]))
;; => [p1__7000#]

So to answer your question: There is no next function in (-> [%]). The number of next functions can be any non-negative number, including zero, which is the case with (-> [%]).

Rulle
  • 4,496
  • 1
  • 15
  • 21
0

@Rulle gives an exhaustive explanation of the details.

May I point out the most important part? Your reference from Clojure.org says:

;; DO NOT DO THIS
#([%])

So, don't do that! It is a silly trick that will only cause confusion & pain. Why would you want that???

Alan Thompson
  • 29,276
  • 6
  • 41
  • 48