gpt4 book ai didi

collections - 对 Clojure 集合的操作

转载 作者:行者123 更新时间:2023-12-04 11:55:14 25 4
gpt4 key购买 nike

我对 Clojure 很陌生,虽然我熟悉函数式语言,主要是 Scala。

我想弄清楚在 Clojure 中操作集合的惯用方法是什么。我对 map 等函数的行为感到特别困惑。 .

在 Scala 中,非常小心地制作 map将始终返回与原始集合相同类型的集合,只要这有意义:

List(1, 2, 3) map (2 *) == List(2, 4, 6)
Set(1, 2, 3) map (2 *) == Set(2, 4, 6)
Vector(1, 2, 3) map (2 *) == Vector(2, 4, 6)

相反,在 Clojure 中,据我所知,大多数操作如 mapfilter即使在急切的数据结构上调用时也是懒惰的。这有奇怪的结果
(map #(* 2 %) [1 2 3])

一个惰性列表而不是一个向量。

虽然我通常更喜欢惰性操作,但我发现上述内容令人困惑。事实上,向量保证了列表不具备的某些性能特征。

假设我使用上面的结果并在其末尾追加。如果我理解正确,则在我尝试追加之前不会对结果进行评估,然后对其进行评估并得到一个列表而不是向量;所以我必须遍历它以追加到最后。当然我可以在之后把它变成一个向量,但这会变得困惑并且可以被忽略。

如果我理解正确, map是多态的,实现它不会有问题,因为它返回向量上的向量,列表上的列表,流上的流(这次使用惰性语义)等等。我想我遗漏了 Clojure 的基本设计及其习语。

What is the reason basic operations on clojure data structures do not preverse the structure?

最佳答案

在 Clojure 中,许多函数都基于 Seq抽象。
这种方法的好处是你不必为每个不同的集合类型编写一个函数——只要你的集合可以被视为一个序列(有头也可能有尾的东西),你可以将它与所有seq 函数。使用 seqs 和输出 seqs 的函数比将其使用限制为特定集合类型的函数更具组合性,因此可重用。在 seq 上编写您自己的函数时,您不需要处理特殊情况,例如:如果用户给我一个向量,我必须返回一个向量等。您的函数将与其他任何函数一样适合 seq 管道序列功能。

map 返回惰性 seq 的原因是设计选择。在 Clojure 中,惰性是许多这些函数结构的默认设置。如果你想要其他行为,比如没有中间集合的并行性,请查看 reducers 库:http://clojure.com/blog/2012/05/08/reducers-a-library-and-model-for-collection-processing.html

就性能而言,map 总是必须在集合上应用 n 次函数,从第一个元素到最后一个元素,因此它的性能总是 O(n) 或更糟。在这种情况下,向量或列表没有区别。懒惰可能会给你带来的好处是,当你只消费列表的第一部分时。如果您必须在 map 输出的末尾附加一些内容,向量确实更有效。您可以使用 mapv (在 Clojure 1.4 中添加)在这种情况下:它接受一个集合并输出一个向量。我会说,如果您有充分的理由,只需担心这些性能优化。大多数时候它不值得。

在此处阅读有关 seq 抽象的更多信息: http://clojure.org/sequences

Clojure 1.4 中添加的另一个返回向量的高阶函数是 filterv .

关于collections - 对 Clojure 集合的操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14126025/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com