我想在Haskell中创建一个基于可变数组的堆(在其他地方找到的基本类)。然而,有些事情我不喜欢我最初的方法:
f
示例函数中使用我的堆时,我必须绕过n
s。将我的堆抽象为一个漂亮的数据类型的最佳方法是什么?我觉得这可以解决我的大部分问题。
buildHeap max_n =
do
arr <- newArray (1, max_n) 0 :: ST s (STArray s Int Int)
return (0, arr)
-- My heap needs to know the array where the elements are stored
-- and how many elements it has
f n = --example use
do
(n1, arr) <- buildHeap n
(n2, _) <- addHeap (n1, arr) 1
(n3, _) <- addHeap (n2, arr) 2
getElems arr
main = print $ runST (f 3)
答案 0 :(得分:5)
您绝对应该将基础表示包装在抽象数据类型中,并且仅提供用于构建和拆分堆数据结构的智能构造函数。
可变结构往往比不可变结构具有更简单的API(因为它们支持较少的好行为)。要了解可变容器类型的合理API,包括如何抽象表示,或许请查看the Judy package。
特别是
API:
new :: JE a => IO (JudyL a)
-- Allocate a new empty JudyL array.
null :: JudyL a -> IO Bool
-- O(1), null. Is the map empty?
size :: JudyL a -> IO Int
-- O(1), size. The number of elements in the map.
lookup :: JE a => Key -> JudyL a -> IO (Maybe a)
-- Lookup a value associated with a key in the JudyL array.
insert :: JE a => Key -> a -> JudyL a -> IO ()
-- Insert a key and value pair into the JudyL array. Any existing key will be overwritten.
delete :: Key -> JudyL a -> IO ()
-- Delete the Index/Value pair from the JudyL array.
您需要支持许多相同的操作,并使用类似的类型签名。
JudyL
的实际基础表示由下式给出:
newtype JudyL a =
JudyL { unJudyL :: MVar (ForeignPtr JudyL_) }
type JudyL_ = Ptr JudyLArray
data JudyLArray
注意我们如何通过锁定底层资源(在这种情况下,指向数据结构的C指针)来提供线程安全性。另外,表示是抽象的,并且对用户不可见,使API保持简单。
答案 1 :(得分:4)
初学者的一般建议 - 从IOArrays而不是STArrays开始,因此您不必担心更高级的类型以及ST带来的其他技巧。然后,在你得到满意的东西之后,如果你愿意,可以考虑如何将它移动到ST。
除此之外,你应该制作自己的ADT而不是元组。
data MutHeap a = MutHeap Int (IOArray Int a)
buildHeap max_n = do
arr <- newArray_ (1, max_n)
return (MutHeap 0 arr)
等