function - Clojure 中是否有标准的参数序列标识函数?

标签 function clojure sequence identity arity

Clojure 标准库中是否有与以下等效的函数?

(fn [& args] args)

如果不是,为什么?

用法示例:
(take 10 (apply (fn [& args] args) (range)))
;=> (0 1 2 3 4 5 6 7 8 9)

;; ironically, map isn't lazy enough, so let's take it up to 11
(defn lazy-map [f & colls]
  (lazy-seq (cons (apply f (map first colls))
                  (apply lazy-map f (map rest colls)))))

(defn transpose [m]
  (apply lazy-map (fn [& args] args) m))

(defn take-2d [rows cols coll]
  (take rows (map (partial take cols) coll)))

(take-2d 3 3 (transpose (map (partial iterate inc) (range))))
;=> ((0 1 2) (1 2 3) (2 3 4))

请注意,我不是在要求诸如 vectorlist 之类的变革性的、急切的功能。

最佳答案

没有这样的功能,你可以随意实现和使用它:

(defn args [& args] args)

(set (map type (apply map args [[1 2 3][4 5 6][7 8 9]])))
=> #{clojure.lang.ArraySeq}

为什么它不是已经可用?

这是一个很少有成果的问题:不仅我们不知道实现者的想法,而且要求他们证明或记录他们为什么没有做某事是不切实际的。有没有考虑过添加这个功能?我们怎么知道?真的有原因,还是只是发生了?

另一方面,我同意 args 感觉更简单,因为它传递了一个已经存在的不可变序列。
我也可以理解您是否认为首先不将参数转换为持久列表更好,即使只是为了简洁。

但这不是它的实现方式,使用 list 的开销真的可以忽略不计(从 ArraySeq 的实例构建时使用 specialized )。
你应该对一个接口(interface)进行编码并且永远不要往幕后看,从这个角度来看,listargs 是等效的,即使它们没有返回相同的结果。

你添加了关于懒惰的评论,你是对的:如果你需要从可变参数函数中获取参数并将其传递给一个对序列进行操作的函数,带有 list 的版本将消耗所有给定的参数,而 args 不会。在某些情况下,就像 (apply list (range)) 一样,您实际上传递了无限数量的参数,这可能会永远挂起。

从这个角度来看,小 args 函数实际上很有趣:您可以从参数移动到实际序列,而不会引入潜在问题。
然而,我不确定这种情况在实践中发生的频率。
事实上,我很难找到一个用例,就 args 而言,参数列表中的懒惰真的很重要。
毕竟,为了传递一个无限序列,唯一的方法 (?) 是使用 apply:
(apply f (infinite))

为了有 args 的用例,这意味着我们希望从参数列表转换回单个列表,以便另一个函数 g 可以将其用作序列,如下所示:
(g (apply args (infinite)))

但在这种情况下,我们可以直接调用:
(g (infinite))

在您的示例中, g 将代表 cons 中的 lazy-map ,但由于 f 在输入中给出,我们不能直接编写 (cons (map ...) ...) 。因此,该示例看起来像是 args 的真正用例,但是您应该大量记录该函数,因为您提供的代码段非常复杂。我倾向于认为给函数提供无限数量的参数是一种代码味道:每个带有 [& args] 签名的函数是否应该避免消耗所有参数,因为给定的序列实际上可能是无限的,就像 lazy-map 那样?我宁愿将单个参数作为这种用法的惰性序列(并在需要时传递 identity)而不是整个参数列表,以阐明意图。但归根结底,我也不强烈反对使用 args

总而言之,除非您设法说服 Rich Hickey 添加 args 作为核心功能,否则我相信几乎没有人会想要依赖仅执行此操作的外部库 1 :它不熟悉,但实现起来也很简单而且大多没用。唯一的奖励是知道您跳过了一个在大多数情况下不需要任何成本的小转换步骤。同样,不必担心必须在向量和列表之间进行选择:它实际上对您的代码没有影响,如果您能证明有必要,您仍然可以稍后修改代码。
关于懒惰,虽然我同意在列表或向量中包装参数对于无界参数列表可能会产生问题,但我不确定这个问题实际上是否在实践中出现。

1 。当然,如果它达到 clojure.core ,每个人都会很快说这是一个最有用且绝对惯用的基本操作

关于function - Clojure 中是否有标准的参数序列标识函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33881765/

相关文章:

MySQL 适当的功能

clojure - 使用宏和doseq来生成spec

Clojure thread-first 宏 (->) 与 thread-last 宏 (->>) 有什么实际区别?

clojure - ClojureScript One 可以做什么?

python - 在 Python 中,如何获得两个列表的交集,同时保留交集的顺序?

javascript - 如何确定从序列中删除子序列的所有可能方式?

java - 如何在 mysql 中手动设置 hibernate 序列?

python - 通过定义的函数减少 numpy 数组的维度

python - Cython 函数指针解引用时间(与直接调用函数相比)

python - 函数迭代的问题