threading macro -> with anonymous functions

Your specific case could have been solved simply using:

(-> 4 (+ 1) (- 1) (+ 1))

where the thread first macro -> takes care of inserting the result of the previous step as the first argument in the "current" function.

The confusion arises from the fact that -> is not a function but a macro and the arguments are treated very differently in this case as explained by other answers.


You can have anonymous functions in Clojure macros. You are having problems, because you are missing some parentheses. :) Your example is edited below.

(-> 4 (#(+ % 1)) (#(- % 1)) (#(+ % 1)))

(this is based on the answer to the question i posted in comments).

the -> macro takes each argument, making it a list if necessary (applying "raw" functions to no args - converting myfunc to (myfunc)), and then inserts the first argument to -> as second argument in each of those lists.

so (-> foo myfunc) becomes (-> foo (myfunc)) becomes (myfunc foo), roughly.

this is all described in the docs for ->.

the problem with anonymous functions is that they are generated by a reader macro as described here (scroll down). that means that #(...) is converted (before normal macro expansion) into (fn [...] ...). which is fine, but, critically, is already a list.

so the macro believes that the anonymous function is already being applied, when in fact it is encountering a function definition (both are lists). and adding the "extra" parens - as described above in the other answer - applies the anonymous function to no args.

the reason for this un-intuitive behaviour is that the dwim (do-what-i-mean, not dwim-witted, although...) heuristic used by the -> macro, added to allow you to supply "bare" functions rather than requiring that you apply them to no args by enclosing them in a list, is just a heuristic - it simply tests for a list - and is confused by the function definition created by the reader macro.

[in my bad tempered opinion, -> is poorly implemented and should instead reject all "bare" functions, instead only accepting function applications; it would then appear more consistent. if not, then at least the docs could be clearer, explaining the motivating semantics behind placing things in lists.]