(部分应用str)和在clojure中的apply-str - >

时间:2010-04-05 01:45:50

标签: variables clojure partial

如果我执行以下操作:

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"

......代码按照我的意图运作。我认为它们是相同的,但显然事实并非如此。有人可以解释为什么这对我来说吗?

5 个答案:

答案 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 applystr已作为前两个参数提供。此函数打印为奇怪的#<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)))

相关部分是在处理两个参数xform时。如果form是seq,则插入x作为该列表中的第二个参数。否则,宏会将formx放入列表本身。这样您就可以使用裸符号作为包含一个符号的列表的简写。

user> (macroexpand '(-> 123 (foo)))
(foo 123)
user> (macroexpand '(-> 123 foo))
(foo 123)