使用匿名函数宏时,mapcat arity错误

时间:2020-07-20 15:58:55

标签: clojure

为什么这样做:

(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)

2 个答案:

答案 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)函数调用的新函数。