为什么这样做:
(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)
发布于 2020-07-20 17:08:08
#(%)等同于(fn [x] (x)),而不是(fn [x] x)。这是问题的核心。每当您不确定特定的读取器语法做什么时,read-string就会非常方便。在您的REPL中尝试(read-string "#(%)")。它应该打印一些类似(fn* [p1__3#] (p1__3#))的东西。p1__3#是一个自由变量,从某种意义上说,我们可以用任何其他不限定的符号替换它,这将是等价的。
就ArityException而言,向量可以称为函数。它们是它们索引的函数。例如,([:a :b :c] 1)返回:b。当被称为函数时,只有偶然性-1是合法的。在这种情况下,使用mapcatting和#(%)调用输入中的每个向量,不带任何参数。这就是导致ArityException的原因。
此外,(mapcat (fn [x] x) ...)与(mapcat identity ...)相同,也与(apply concat ...)相同。你可能想用这个代替。
发布于 2020-07-20 16:00:23
你在寻找:
(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 中的父类绝不意味着分组(我知道,这是一个很难摆脱的习惯!)
演示:
(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)函数调用的新函数。
https://stackoverflow.com/questions/62999351
复制相似问题