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))
请注意,我并不是在要求 vector
或 list
等具有变革性的急切功能。
有identity
功能。它需要一个参数,并且只是 return 那个参数。 Clojure 的 identity
是单元数。
用法:
(identity 4) ;=> 4
(identity [1 2 3 4]) ;=> [1 2 3 4]
我认为使用具有可变元数的恒等函数没有多大意义,因为 Clojure 函数 return 只有一个值。如果你想 return 来自一个函数的多个值,那么你可以将它们包装在一个 seq 中,稍后你可以解构它。在那种情况下你可以有这样的东西:
(defn varity-identity [& args]
(map identity args))
(varity-identity 1 2 3 4 5) ;=> (1 2 3 4 5)
希望对您有所帮助。
暂无此功能,您可以随意实现和使用:
(defn args [& args] args)
(set (map type (apply map args [[1 2 3][4 5 6][7 8 9]])))
=> #{clojure.lang.ArraySeq}
为什么还没有?
这个问题很少有成果:我们不仅不知道实施者的想法,而且要求他们证明或记录为什么他们没有不也是不切实际的做一点事。是否考虑过添加此功能?我们怎么知道?真的有原因,还是只是发生了?
另一方面,我同意 args
感觉更简单,因为它传递了一个已经存在的不可变序列。
如果您认为 not 首先将参数转换为持久列表更好,我也能理解,如果只是为了节约。
但这不是它的实现方式,使用 list
的开销真的可以忽略不计(从 ArraySeq
的实例构建时 specialized )。
您应该针对界面进行编码,永远不要看幕后情况,从这个角度来看,list
和 args
是 等效的 ,即使它们确实如此不 return 相同 结果。
你添加了关于懒惰的评论,你是对的:如果你需要从可变参数函数中获取参数并将其传递给对序列进行操作的函数,带有 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
,每个人都会很快说这是最有用且绝对惯用的基本操作
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))
请注意,我并不是在要求 vector
或 list
等具有变革性的急切功能。
有identity
功能。它需要一个参数,并且只是 return 那个参数。 Clojure 的 identity
是单元数。
用法:
(identity 4) ;=> 4
(identity [1 2 3 4]) ;=> [1 2 3 4]
我认为使用具有可变元数的恒等函数没有多大意义,因为 Clojure 函数 return 只有一个值。如果你想 return 来自一个函数的多个值,那么你可以将它们包装在一个 seq 中,稍后你可以解构它。在那种情况下你可以有这样的东西:
(defn varity-identity [& args]
(map identity args))
(varity-identity 1 2 3 4 5) ;=> (1 2 3 4 5)
希望对您有所帮助。
暂无此功能,您可以随意实现和使用:
(defn args [& args] args)
(set (map type (apply map args [[1 2 3][4 5 6][7 8 9]])))
=> #{clojure.lang.ArraySeq}
为什么还没有?
这个问题很少有成果:我们不仅不知道实施者的想法,而且要求他们证明或记录为什么他们没有不也是不切实际的做一点事。是否考虑过添加此功能?我们怎么知道?真的有原因,还是只是发生了?
另一方面,我同意 args
感觉更简单,因为它传递了一个已经存在的不可变序列。
如果您认为 not 首先将参数转换为持久列表更好,我也能理解,如果只是为了节约。
但这不是它的实现方式,使用 list
的开销真的可以忽略不计(从 ArraySeq
的实例构建时 specialized )。
您应该针对界面进行编码,永远不要看幕后情况,从这个角度来看,list
和 args
是 等效的 ,即使它们确实如此不 return 相同 结果。
你添加了关于懒惰的评论,你是对的:如果你需要从可变参数函数中获取参数并将其传递给对序列进行操作的函数,带有 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
,每个人都会很快说这是最有用且绝对惯用的基本操作