繁体   English   中英

Clojure中是否有标准的参数序列同一性函数?

[英]Is there a standard argument sequence identity function in Clojure?

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 )。 您应该对接口进行编码,并且永远不要掩盖,从这个角度来看,即使listargs不会返回相同的结果,它们也是等效的

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

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

(apply f (infinite))

为了为args提供用例,这意味着我们要从参数列表转换回单个列表,以便另一个函数g可以将其用作序列,如下所示:

(g (apply args (infinite)))

但是在那种情况下,我们可以直接调用:

(g (infinite))

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

综上所述,除非您设法说服Rich Hickey将args作为核心函数添加,否则我相信几乎没有人会希望依赖于这样做的外部库1 :它不熟悉,但实现起来却很琐碎,而且大多数情况下无用。 唯一的收获就是知道您跳过了一些转换步骤,在大多数情况下,该步骤不会花费任何费用。 同样,不必担心必须在向量和列表之间进行选择:它实际上对代码没有影响,并且如果可以证明有必要的话,您仍然可以稍后修改代码。 关于懒惰,尽管我同意将参数包装在列表或向量中对于无限制的参数列表可能会出现问题,但我不确定问题实际上是否会在实际中出现。


1 当然,如果它到达clojure.core ,每个人都会很快地说这是最有用的操作,并且绝对是惯用的</ cynic>

identity功能。 它接受一个参数,然后返回该参数。 Clojure的identity不过是单身。

用法:

(identity 4) ;=> 4

(identity [1 2 3 4]) ;=> [1 2 3 4]

我认为使用具有可变Arity的identity函数没有多大意义,因为Clojure函数仅返回一个值。 如果要从一个函数返回多个值,则可以将它们包装在一个seq中,以便以后进行分解。 在这种情况下,您可以拥有以下内容:

(defn varity-identity [& args]
    (map identity args))

(varity-identity 1 2 3 4 5) ;=> (1 2 3 4 5)

希望这可以帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM