我会直接了解它 - 有没有办法在Haskell中拥有动态大小的常量时间访问数据结构,就像任何其他命令式语言中的数组一样?
我确信在某个地方有一个模块可以为我们神奇地做到这一点,但我希望能够以一种功能性的方式对一个人如何做到这一点的一般性解释:)
据我所知,Map
使用二叉树表示,因此它具有 O(log(n))
访问时间,当然列表 {{1访问时间。。
另外,如果我们这样做它是不可变的,它会是纯粹的,对吧?
我有什么想法可以解决这个问题(超出模板Haskell之类的O(n)
之类的东西)?
答案 0 :(得分:7)
如果您的密钥与Int
同构,那么您可以使用IntMap,因为其大多数操作都是O(min(n,W))
,其中n
是元素的数量,{{1} {}}中的位数(通常为32或64),这意味着当集合变大时,每个单独操作的成本会收敛到常量。
答案 1 :(得分:5)
Haskell中动态大小的常量时间访问数据结构,
等等。
对于关联结构,您可以选择:
具有各种不同的对数复杂度和常数因子。
所有这些都是关于黑客的。
答案 2 :(得分:2)
除了其他好的答案之外,可能有用的说法是:
当限于代数数据类型和纯度时,全部动态 大小的数据结构必须至少具有对数最坏情况访问 时间。
就个人而言,我喜欢将此称为纯度价格。
Haskell为您提供了三种主要方法:
答案 3 :(得分:1)
确实,没有编译器/运行时魔术,就无法在Haskell中拥有恒定时间的访问数组。
但是,这不是(仅仅是)因为Haskell具有功能。 Java和C#中的数组也需要运行时魔术。在Rust中,您也许可以用不安全的代码来实现它们,但不能在安全的Rust中实现。
事实是,任何一种不允许您分配动态大小的内存,或者不允许您使用指针的语言都将需要运行时魔术来实现数组。
这不包括任何安全语言,无论是面向对象的还是功能的。
Haskell和eg之间的唯一区别。就数组而言,Java在Haskell中远没有Java有用,但是在Java数组中,数组是我们所做的一切的核心,因此我们甚至都没有注意到它们是魔术。
虽然Haskell对数组比例如eg需要更多的魔术,但是有一种方法。 Java。
使用Java,您可以初始化一个空数组(需要魔术),然后用值填充(不需要)。
使用Haskell,这显然会违反不变性。因此,任何数组都必须使用其值进行初始化。因此,编译器的魔力不仅仅在于为您提供空的内存块供您索引。它还要求您提供一种使用值初始化数组的方法。因此,数组的创建和初始化必须是一个步骤,完全由编译器处理。