如果我执行以下操作:
user=> (-> ["1" "2"] (partial apply str))
#<core$partial__5034$fn__5040 clojure.core$partial__5034$fn__5040@d4dd758>
......我得到了部分功能。但是,如果我将它绑定到变量:
user=> (def apply-str (partial apply str))
#'user/apply-str
user=> (-> ["1" "2" "3"] apply-str)
"123"
......代码按照我的意图运作。我认为它们是相同的,但显然事实并非如此。有人可以解释为什么这对我来说吗?
答案 0 :(得分:6)
- &GT;是一个宏,因此它不必遵循您在应用程序方面所期望的规则。宏在评估表单之前转换源。尝试宏扩展表单:
user> (macroexpand '(-> ["1" "2"] (partial apply str)))
(partial ["1" "2"] apply str)
你想通过' - &gt;'在这里实现什么?宏?
编辑:请注意:
user> ((partial apply str) ["1" "2"])
"12"
答案 1 :(得分:5)
你根本不需要这样做。
(->> ["1" "2" "3"] (apply str))
为什么不这样做呢?
答案 2 :(得分:4)
第一个表达式(-> ["1" "2"] (partial apply str))
扩展为:
(partial ["1" "2"] apply str)
这基本上意味着:
从["1" "2"]
创建一个函数(它也是一个函数,因为向量是索引键的函数!),其中Vars apply
和str
已作为前两个参数提供。此函数打印为奇怪的#<core$partial...>
字符串。
只有在调用此函数时才会出现IllegalArgumentException,因为向量只接受一个整数参数,而不是两个Var参数。
答案 3 :(得分:1)
宏 - &gt; 通过表单将expr作为第二个参数进行线程化。在你的情况下,最终扩展到:(partial ["1" "2"] apply str)
,创建一个基于向量的parital函数。
但是你希望调用基于apply和str的线程函数,因此需要:
(-> ["1" "2"] ((partial apply str)))
嗯:这段代码让我很困惑,而不是惯用的Clojure。
答案 4 :(得分:0)
->
宏在第二个版本中添加apply-str
周围的parens,这就是宏扩展到最终调用函数的代码的原因。查看->
的源代码,您可以看到:
(defmacro ->
"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."
([x] x)
([x form] (if (seq? form)
(with-meta `(~(first form) ~x ~@(next form)) (meta form))
(list form x)))
([x form & more] `(-> (-> ~x ~form) ~@more)))
相关部分是在处理两个参数x
和form
时。如果form
是seq,则插入x
作为该列表中的第二个参数。否则,宏会将form
和x
放入列表本身。这样您就可以使用裸符号作为包含一个符号的列表的简写。
user> (macroexpand '(-> 123 (foo)))
(foo 123)
user> (macroexpand '(-> 123 foo))
(foo 123)