是否存在有用的 Haskell HashMap/HashTable/Dictionary 库?
Does a useful Haskell HashMap/HashTable/Dictionary library exist?
我正在寻找无 monad 的常量访问查询 O(1) 关联数组。
考虑假设类型:
data HT k v = ???
我想构造一次immutable结构:
fromList :: Foldable t, Hashable k => t (k,v) -> HT k v
我想随后以恒定时间访问重复查询它::
lookup :: Hashable k => HT k v -> k -> Maybe v
似乎有两个候选库不合格:
unordered-containers
unordered-containers
包含 HashMap
类型的严格和惰性变体。 HashMap
都有 O(log n) 查询,如 lookup
function. This query access time appears to be due to the construction of the HashMap
types, which have an internal tree structure allowing for O(log n) insert
功能所述。许多用例的可理解设计权衡,但由于我不需要 mutable HashMap
这种权衡阻碍了我的用例。
hashtables
hashtables
包含一个 HashTable
类型-class 和三个具有不同 table 构造策略的实例类型。这个库的 type-class 定义了一个常量时间 O(1) lookup
函数定义,但它永远嵌入在 ST
monad 中。没有办法 "freeze" 有状态 HashTable
实现并且有一个 lookup
函数没有嵌入有状态 monad。当整个计算都包含在一个状态 monad 中时,库的 type-class 接口设计得很好,但这种设计对我的用例来说是不合适的table。
是否存在一些其他定义类型和函数的库,这些库可以构造一个 immutable 常量访问查询 O(1) 未嵌入的关联数组有状态的 monad?
是否存在一些方法来包装或修改这些现有的基于散列的库以生成 immutable 常量访问查询 O(1) 关联数组没有嵌入到有状态的 monad 中?
您想要的图书馆是……unordered-containers
。或者只是 containers
中的普通旧 Data.Map
,如果您愿意的话。
unordered-containers
documentation 中的注释解释了为什么您不应该担心 O(log n) 时间复杂度查找:
Many operations have a average-case complexity of O(log n). The implementation uses a large base (i.e. 16) so in practice these operations are constant time.
这是某些类型的函数式数据结构的常见做法,因为它允许良好的共享属性,同时还具有良好的时间复杂度。 log16 即使对于非常大的 n 仍然会产生 非常小的 数字,所以你几乎总是可以处理那些复杂性为“有效恒定时间”。
如果这曾经是您应用程序的瓶颈,当然,请使用其他方法,但我发现这不太可能。毕竟,log16(1,000,000) 略低于 5,因此您的查找时间不会增长得很快。处理所有这些数据将花费比查找开销更多的时间。
一如既往:个人资料第一。如果你有一个绝对需要世界上最快的哈希映射的问题,你可能需要一个命令式哈希映射,但对于我遇到过的每一个案例,函数式的都可以正常工作。
您应该听从 Alexis 的建议并使用 unordered-containers
。如果你真的想要保证有 Θ(1)
lookup
s 的东西,你可以使用 [=15] 定义来自 hashtables
的任何哈希 table 类型的自己的冻结版本=],但这不是很优雅。例如:
module HT
( HT
, fromList
, lookup
) where
import qualified Data.HashTable.IO as H
import Data.Hashable (Hashable)
import Data.Foldable (toList)
import System.IO.Unsafe (unsafePerformIO)
import Prelude hiding (lookup)
newtype HT k v = HT (H.BasicHashTable k v)
fromList :: (Foldable t, Eq k, Hashable k) => t (k, v) -> HT k v
fromList = HT . unsafePerformIO . H.fromList . toList
lookup :: (Eq k, Hashable k) => HT k v -> k -> Maybe v
lookup (HT h) k = unsafePerformIO $ H.lookup h k
上面unsafePerformIO
的两种用法应该是安全的。因为将 HT
导出为抽象类型至关重要。
Does there exist some other library which defines types and functions which can construct an immutable constant access query O(1) associative array that is not embedded in a stateful monad?
在这个时间点,答案仍然是否定的。
截至 2019 年底,有一个高效的基于 IO
的 hashtable
软件包,具有不错的基准。
您所描述的内容似乎与纯粹的、不可变的 Data.Array
construction is possible. See Data.Array.Base
一样可行,因为这是通过 unsafe*
运算符实现的。 Data.Array
是用边界定义的,我最初的想法是,如果允许无边界增长,一个纯粹的、不可变的哈希表可能会出现 GC 问题。
我正在寻找无 monad 的常量访问查询 O(1) 关联数组。
考虑假设类型:
data HT k v = ???
我想构造一次immutable结构:
fromList :: Foldable t, Hashable k => t (k,v) -> HT k v
我想随后以恒定时间访问重复查询它::
lookup :: Hashable k => HT k v -> k -> Maybe v
似乎有两个候选库不合格:
unordered-containers
unordered-containers
包含 HashMap
类型的严格和惰性变体。 HashMap
都有 O(log n) 查询,如 lookup
function. This query access time appears to be due to the construction of the HashMap
types, which have an internal tree structure allowing for O(log n) insert
功能所述。许多用例的可理解设计权衡,但由于我不需要 mutable HashMap
这种权衡阻碍了我的用例。
hashtables
hashtables
包含一个 HashTable
类型-class 和三个具有不同 table 构造策略的实例类型。这个库的 type-class 定义了一个常量时间 O(1) lookup
函数定义,但它永远嵌入在 ST
monad 中。没有办法 "freeze" 有状态 HashTable
实现并且有一个 lookup
函数没有嵌入有状态 monad。当整个计算都包含在一个状态 monad 中时,库的 type-class 接口设计得很好,但这种设计对我的用例来说是不合适的table。
是否存在一些其他定义类型和函数的库,这些库可以构造一个 immutable 常量访问查询 O(1) 未嵌入的关联数组有状态的 monad?
是否存在一些方法来包装或修改这些现有的基于散列的库以生成 immutable 常量访问查询 O(1) 关联数组没有嵌入到有状态的 monad 中?
您想要的图书馆是……unordered-containers
。或者只是 containers
中的普通旧 Data.Map
,如果您愿意的话。
unordered-containers
documentation 中的注释解释了为什么您不应该担心 O(log n) 时间复杂度查找:
Many operations have a average-case complexity of O(log n). The implementation uses a large base (i.e. 16) so in practice these operations are constant time.
这是某些类型的函数式数据结构的常见做法,因为它允许良好的共享属性,同时还具有良好的时间复杂度。 log16 即使对于非常大的 n 仍然会产生 非常小的 数字,所以你几乎总是可以处理那些复杂性为“有效恒定时间”。
如果这曾经是您应用程序的瓶颈,当然,请使用其他方法,但我发现这不太可能。毕竟,log16(1,000,000) 略低于 5,因此您的查找时间不会增长得很快。处理所有这些数据将花费比查找开销更多的时间。
一如既往:个人资料第一。如果你有一个绝对需要世界上最快的哈希映射的问题,你可能需要一个命令式哈希映射,但对于我遇到过的每一个案例,函数式的都可以正常工作。
您应该听从 Alexis 的建议并使用 unordered-containers
。如果你真的想要保证有 Θ(1)
lookup
s 的东西,你可以使用 [=15] 定义来自 hashtables
的任何哈希 table 类型的自己的冻结版本=],但这不是很优雅。例如:
module HT
( HT
, fromList
, lookup
) where
import qualified Data.HashTable.IO as H
import Data.Hashable (Hashable)
import Data.Foldable (toList)
import System.IO.Unsafe (unsafePerformIO)
import Prelude hiding (lookup)
newtype HT k v = HT (H.BasicHashTable k v)
fromList :: (Foldable t, Eq k, Hashable k) => t (k, v) -> HT k v
fromList = HT . unsafePerformIO . H.fromList . toList
lookup :: (Eq k, Hashable k) => HT k v -> k -> Maybe v
lookup (HT h) k = unsafePerformIO $ H.lookup h k
上面unsafePerformIO
的两种用法应该是安全的。因为将 HT
导出为抽象类型至关重要。
Does there exist some other library which defines types and functions which can construct an immutable constant access query O(1) associative array that is not embedded in a stateful monad?
在这个时间点,答案仍然是否定的。
截至 2019 年底,有一个高效的基于 IO
的 hashtable
软件包,具有不错的基准。
您所描述的内容似乎与纯粹的、不可变的 Data.Array
construction is possible. See Data.Array.Base
一样可行,因为这是通过 unsafe*
运算符实现的。 Data.Array
是用边界定义的,我最初的想法是,如果允许无边界增长,一个纯粹的、不可变的哈希表可能会出现 GC 问题。