簡體   English   中英

索引Haskell數據結構以進行查詢

[英]Indexing a Haskell data structure for queries

我有一個Dog記錄的Data.Vector ,每個記錄都標識了所述狗所居住的House 我需要一個查找例程來查找屋子中所有隱約可見的狗,如下所示,但我需要進行恆定時間查找,而這是第一個版本所不能提供的。

dogs_by_houses dogs h = [ d | d <- Vec.toList dogs, h == house d ]

據我了解,優化Haskell代碼的一條中心規則是,編譯器僅在將其包含在lambda表達式內部后才計算每個表達式。 因此,在綁定h之前,我必須在dogs_by_houses dogs表達式內為此特定的dogs構建一個查找表。

我認為Data.Vector是完成此任務的最佳工具,盡管顯然您無法像使用C ++向量那樣縮小它們。 我大致實現如下:

dogs_by_houses :: Vec.Vector Dog -> Int -> [Dog]
dogs_by_houses dogs = let {
        dog_house = house_id . house ;
        v0 = Vec.replicate (maximum . map dog_house $ Vec.toList dogs) [] ;
        f v d = let { h = dog_house d } in v // [(h,d:v!h)] ;
        dbh = Vec.foldl' f v0 dogs
   } in (dbh !)

在優化方面,這有什么愚蠢的選擇嗎? 我猜想像dbh這樣的變量上的嚴格性標簽沒有太大幫助,因為按照定義,必須在dbh有意義之前遍歷dogs

使用MVector進行create並折疊返回修改后的不可變矢量,這有什么大的優勢? 我所有的企圖使用MVectorcreate迄今出來絕不夠簡明,各層do S或fold (>>)同樣的結構或什么的。 我認為即使沒有顯式指定MVector ,編譯器也應該只在適當位置構建dbh

用列表無法實現該算法嗎? 您偶爾會看到人們建立無窮的素數的無限列表,然后選擇帶有primes !! n的第n個素primes !! n primes !! n 我假設以這種方式檢索第n個素數需要每次遍歷列表中的前n個素數。 相反,我注意到GHC將字符串存儲為C字符串,而不是列表。 編譯器會簡單地將已知列表元素表示為數組,而不是遍歷每個列表嗎?

更新:

我已經使用了Paul Johnson和Louis Wasserman的答案來構建以這種方式索引任意向量的函數,因為我必須基於幾個不同的索引函數來這樣做。

vector_indexer idx vec = \i -> (Vec.!) t i
  where m = maximum $ map idx $ Vec.toList vec
        t = Vec.accumulate (flip (:)) (Vec.replicate m []) 
               $ Vec.map (\v -> (idx v, v)) vec
dogs_by_houses = vector_indexer (house_id . house)

我尚未對此進行概要分析,但最終。 我希望有人必須編寫my_d_by_h = dogs_by_houses my_dogs並調用my_d_by_h才能從索引中受益。

我會用

Vec.accumulate (:) (Vec.replicate maxHouse []) 
  (Vec.map (\ d -> (dog_house d, d)) dogs)

它肯定會最多分配一個中間向量,我懷疑它可能很聰明,根本不分配任何中間向量。

我曾經被一個討厭的陷阱捉住了,做這樣的事情。 我使用Data.Map.Map作為查找表,但是原理是相同的。 我的函數獲取了一個鍵-值對列表,構造了一個Map,並返回了lookup函數。 它是這樣的:

makeTable :: [(Key, Value)] -> Key -> Value
makeTable pairs = ((fromList pairs) !)

對我來說似乎很明顯,我可以寫一些類似的東西

myTable = makeTable [("foo", fooValue), ("bar", barValue)  ... and so on]

然后我可以說一個O(log N)查找

v = myTable "foo"

但是,GHC實際上所做的是從每個呼叫的列表中重建整個Map。 當您以這種方式創建部分應用程序時,GHC不會嘗試找出它可以從其獲取的參數中得出哪些值,它僅存儲原始參數並為每次調用完成整個功能。 完全合理的行為,但不是我想要的。

我必須寫的是:

makeTable pairs = \k -> table ! k
   where table = fromList pairs

我想您將不得不做同樣的事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM