Anonymous Functions in Thread Macros


While adding the live reload feature to Clay, I encountered a problem of applying anonymous functions to thread macros. For example, below is a simple snippet trying to wrap the input directory as a vector with the help of thread macro, but surprisingly, it errors out. After some searching, I figured out that I need to put the anonymous function into another pair of parentheses:

(-> "/tmp/"
    #(if (vector? %) % [%]))
;; => Syntax error (ClassCastException) compiling fn* at (simple4all.clj:19:1).
;;    class java.lang.String cannot be cast to class clojure.lang.ISeq (java.lang.String is in module java.base of loader 'bootstrap'; clojure.lang.ISeq is in unnamed module of loader 'app')

(-> "/tmp/"
    (#(if (vector? %) % [%])))
;; => ["/tmp/"]

Paul has a nice explanation on Stack Overflow, thread macros need the function forms to be lists, but anonymous functions are already lists, so the first expression, "/tmp/" in this example, will just be inserted into that list, just as illustrated below:

(macroexpand '#(if (vector? %) % [%]))
;; => (fn* [p1__11055#] (if (vector? p1__11055#) p1__11055# [p1__11055#]))

(macroexpand '(-> "/tmp/"
                  #(if (vector? %) % [%])))
;; => (fn*
;;     "/tmp/"
;;     [p1__11079#]
;;     (if (vector? p1__11079#) p1__11079# [p1__11079#]))

See also

comments powered by Disqus