the -> 宏和偏函数
the -> macro and partial function
为什么我不能在 ->
的链式调用中使用部分函数或匿名函数?
(->
"123"
seq
sort
reverse
(partial apply str))
=> #<core$partial$fn__4230 clojure.core$partial$fn__4230@335f63af>
我原以为会创建部分函数并立即将其应用于前一个函数的结果,但实际上它自己返回了。
具有一个参数的简单函数链接当然可以正常工作:
(->
"123"
seq
sort
reverse
clojure.string/join)
->
宏定义为:
(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.
因此 (apply str) 产生错误,因为前一个函数的列表作为第二个参数输入:
(->
"123"
seq
sort
reverse
(apply str))
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IFn clojure.core/apply (core.clj:624)
相反,应该使用适用于最后一项的宏 ->>:
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.
然后 apply
的解决方案如下所示:
(->>
"123"
seq
sort
reverse
(apply str))
=> "321"
更新:->
和 ->>
的扩展版本:
(macroexpand-1 '(->>
"123"
seq
sort
reverse
(apply str)))
=> (apply str (reverse (sort (seq "123"))))
正如您从扩展版本中看到的那样,唯一不同的是形式 (apply str) 的解释方式。使用 ->
插入第二个项目,而 ->>
插入最后一个项目。
(macroexpand-1 '(->
"123"
seq
sort
reverse
(apply str)))
=> (apply (reverse (sort (seq "123"))) str)
由于 ->
和 ->>
只是宏,您可以使用 macroexpand-1
测试 ->
扩展到的内容(注意引号 ')
user=> (macroexpand-1 '(->
"123"
seq
sort
reverse
(partial apply str)))
(partial (reverse (sort (seq "123"))) apply str)
这就是为什么你得到一个函数而不是一个字符串 - 结果是从 reverse
和 apply
str
返回的集合(它是一个函数)的一部分作为参数。
如果出于某种原因你需要在 ->
中应用一个函数,你应该用括号括起来:
user=> (macroexpand-1 '(->
"123"
((partial sort)) ; we add parens around so -> have plase to insert
))
((partial sort) "123")
或者您可以使用 ->>
宏,因为它的作用与 partial
相同:
((partial str "hello ") "world")
"hello world"
和
(->> (str "hello ") "world") ; expands to (str "hello " "world")
"hello world"
为什么我不能在 ->
的链式调用中使用部分函数或匿名函数?
(->
"123"
seq
sort
reverse
(partial apply str))
=> #<core$partial$fn__4230 clojure.core$partial$fn__4230@335f63af>
我原以为会创建部分函数并立即将其应用于前一个函数的结果,但实际上它自己返回了。
具有一个参数的简单函数链接当然可以正常工作:
(->
"123"
seq
sort
reverse
clojure.string/join)
->
宏定义为:
(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.
因此 (apply str) 产生错误,因为前一个函数的列表作为第二个参数输入:
(->
"123"
seq
sort
reverse
(apply str))
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IFn clojure.core/apply (core.clj:624)
相反,应该使用适用于最后一项的宏 ->>:
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.
然后 apply
的解决方案如下所示:
(->>
"123"
seq
sort
reverse
(apply str))
=> "321"
更新:->
和 ->>
的扩展版本:
(macroexpand-1 '(->>
"123"
seq
sort
reverse
(apply str)))
=> (apply str (reverse (sort (seq "123"))))
正如您从扩展版本中看到的那样,唯一不同的是形式 (apply str) 的解释方式。使用 ->
插入第二个项目,而 ->>
插入最后一个项目。
(macroexpand-1 '(->
"123"
seq
sort
reverse
(apply str)))
=> (apply (reverse (sort (seq "123"))) str)
由于 ->
和 ->>
只是宏,您可以使用 macroexpand-1
测试 ->
扩展到的内容(注意引号 ')
user=> (macroexpand-1 '(->
"123"
seq
sort
reverse
(partial apply str)))
(partial (reverse (sort (seq "123"))) apply str)
这就是为什么你得到一个函数而不是一个字符串 - 结果是从 reverse
和 apply
str
返回的集合(它是一个函数)的一部分作为参数。
如果出于某种原因你需要在 ->
中应用一个函数,你应该用括号括起来:
user=> (macroexpand-1 '(->
"123"
((partial sort)) ; we add parens around so -> have plase to insert
))
((partial sort) "123")
或者您可以使用 ->>
宏,因为它的作用与 partial
相同:
((partial str "hello ") "world")
"hello world"
和
(->> (str "hello ") "world") ; expands to (str "hello " "world")
"hello world"