问题
Why can't I use a partial function or an anonymous function in a chained call with ->
?
(->
"123"
seq
sort
reverse
(partial apply str))
=> #<core$partial$fn__4230 clojure.core$partial$fn__4230@335f63af>
I would have thought the partial function would be created and immediately applied to the previous function's result, but it's actually returned itself.
A simple chaining of functions with one parameter of course works without problems:
(->
"123"
seq
sort
reverse
clojure.string/join)
回答1:
As ->
and ->>
are just macros, you can test what ->
expands to with macroexpand-1
(note the quote ')
user=> (macroexpand-1 '(->
"123"
seq
sort
reverse
(partial apply str)))
(partial (reverse (sort (seq "123"))) apply str)
So that's why you get a function instead of a string - result is partial of collection (which is a function) returned from reverse
and apply
str
as arguments.
If for some reason you need to apply a funcion in ->
, you should wrap it in parens:
user=> (macroexpand-1 '(->
"123"
((partial sort)) ; we add parens around so -> have plase to insert
))
((partial sort) "123")
Or you can use ->>
macro, as it is doing same work as partial
here:
((partial str "hello ") "world")
"hello world"
and
(->> (str "hello ") "world") ; expands to (str "hello " "world")
"hello world"
回答2:
The ->
macro is defined as:
(doc ->)
-------------------------
clojure.core/->
([x & forms])
Macro
Threads the expr through the forms. Inserts x as the
second item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
second item in second form, etc.
Therefore (apply str) yields an error, because the list from the former function is entered as the second argument:
(->
"123"
seq
sort
reverse
(apply str))
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IFn clojure.core/apply (core.clj:624)
Instead one should use the macro ->>, which applies to the last item:
clojure.core/->>
([x & forms])
Macro
Threads the expr through the forms. Inserts x as the
last item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
last item in second form, etc.
Then the solution with apply
looks like this:
(->>
"123"
seq
sort
reverse
(apply str))
=> "321"
UPDATE: expanded version of the ->
and ->>
:
(macroexpand-1 '(->>
"123"
seq
sort
reverse
(apply str)))
=> (apply str (reverse (sort (seq "123"))))
As you can see from the expanded versions, there's only a difference in how the form (apply str) is interpreted. With ->
the second item is inserted while ->>
inserts the last item.
(macroexpand-1 '(->
"123"
seq
sort
reverse
(apply str)))
=> (apply (reverse (sort (seq "123"))) str)
来源:https://stackoverflow.com/questions/29188854/the-macro-and-partial-function