为什么这样做:
(mapcat (fn [x] x) [[1] [2 3] [[4 5 6]]])
但这会导致人为错误吗?
(mapcat #(%) [[1] [2 3] [[4 5 6]]])
错误是:
ArityException错误的args(0)数传递给:PersistentVector clojure.lang.AFn.throwArity(AFn.java:429)
答案 0 :(得分:4)
(fn [x] (x))
等效于(fn [x] x)
,而不等效于read-string
。这是问题的核心。每当您不确定特定的阅读器语法有什么用时,(read-string "#(%)")
就非常有用。在您的REPL中尝试(fn* [p1__3#] (p1__3#))
。它应该打印类似p1__3#
的内容。 ArityException
是一个自由变量,从某种意义上说,我们可以将其替换为任何其他不合格的符号,并且它是等效的。
就([:a :b :c] 1)
而言,向量可以称为函数。它们是它们索引的功能。例如,:b
返回mapcat
。当作为函数调用时,只有arity-1是合法的。在这种情况下,用#(%)
进行ArityException
的调用会在输入中不带任何参数的情况下调用每个向量。这就是导致(mapcat (fn [x] x) ...)
的原因。
此外,(mapcat identity ...)
与(apply concat ...)
与{{1}}相同。您可能要改用它。
答案 1 :(得分:0)
您正在寻找:
(mapcat #(identity %) [[1] [2 3] [[4 5 6]]])
这显示了进度:
(ns tst.demo.core
(:use tupelo.core tupelo.test) )
(dotest
(let [data [[1]
[2 3]
[[4 5 6]]]]
(is= [1 2 3 [4 5 6]]
(mapcat (fn [x] x) data)
(mapcat (fn [x] (identity x)) data)
(mapcat #(identity %) data))))
使用#(%)
时,您实际上是在说:
([2]) ; missing arg
这是如何理解它
(dotest
(let [data [0 1 2 3 4]]
(is= 2 (get data 2))
(is= 2 (data 2))
(is= 2 ([0 1 2 3 4] 2))
(throws? ([0 1 2 3 4]))))
在Clojure中,看到(xxxxx)
之类的括号表示“函数调用”。就像在Java中一样,看到xxxxx()
意味着“函数调用”。 Clojure中的Parens 从不故意 分组(我知道,这是一个很难摆脱的习惯!)。
演示:
(dotest
(let [the-answer-fn (fn [& args] 42)
fn-identity (fn [x] x)
fn-caller (fn [x] (x))]
(is= 42 (the-answer-fn))
(is= 3 (identity 3))
(is= 3 (fn-identity 3))
(is= 42 (fn-caller the-answer-fn))
(is (fn? #(the-answer-fn))) ; it always returns a function
(throws? (fn-caller 3))))
请注意,#(xxx)
阅读器宏只是的简写形式
(fn [] (xxx))
因此,它调用它的主体。作为一种记忆辅助,只需假装#
不存在。其余部分显示发生的情况。
另外,请记住,您将返回包装(xxx)
函数调用的新函数。