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)

这就是为什么你得到一个函数而不是一个字符串 - 结果是从 reverseapply 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"