[英]Haskell: How to use a HashMap in a main function
懇請您的幫助,加快以下程序的速度:
main = do
jobsToProcess <- fmap read getLine
forM_ [1..jobsToProcess] $ \_ -> do
[r, k] <- fmap (map read . words) getLine :: IO [Int]
putStrLn $ doSomeReallyLongWorkingJob r k
可能有很多相同的工作要做,但是這不是我修改輸入的決定,因此我嘗試使用Data.HashMap
備份已處理的工作。 我已經優化了doSomeReallyLongWorkingJob
函數中的算法,但是現在看來,它和C一樣快。
但不幸的是,我似乎無法實現簡單的緩存而不會產生很多錯誤。 我需要一個簡單的類型為HashMap (Int, Int) Int
緩存,但是每次括號太多或太少時。 而且,如果我設法定義緩存,那么我就會陷入將數據放入緩存或從緩存中檢索數據的問題,這會導致很多錯誤。
我已經在Google上搜索了幾個小時,但似乎被卡住了。 順便說一句: longrunner
的結果也是一個Int
。
進行緩存操作的有狀態操作非常簡單。 首先一些樣板:
{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.State
import Data.Map (Map)
import qualified Data.Map as M
import Debug.Trace
我將使用Data.Map
,但是您當然可以在哈希映射或任何類似的數據結構中替換,而不會帶來太多麻煩。 我長時間運行的計算只會將其參數加起來。 我將使用trace
來顯示何時執行此計算。 輸入重復的輸入后,我們希望不要看到trace
的輸出。
reallyLongRunningComputation :: [Int] -> Int
reallyLongRunningComputation args = traceShow args $ sum args
現在,緩存操作將只是查詢我們之前是否已經看到過給定的輸入。 如果有,我們將返回預先計算出的答案; 否則,我們現在將計算出答案並將其存儲。
cache :: (MonadState (Map a b) m, Ord a) => (a -> b) -> a -> m b
cache f x = do
mCached <- gets (M.lookup x)
case mCached of
-- depending on your goals, you may wish to force `result` here
Nothing -> modify (M.insert x result) >> return result
Just cached -> return cached
where
result = f x
現在, main
功能只是在適當的輸入上調用cache reallyLongRunningComputation
。
main = do
iterations <- readLn
flip evalStateT M.empty . replicateM_ iterations
$ liftIO getLine
>>= liftIO . mapM readIO . words
>>= cache reallyLongRunningComputation
>>= liftIO . print
讓我們在ghci中嘗試一下!
> main
5
1 2 3
[1,2,3]
6
4 5
[4,5]
9
1 2
[1,2]
3
1 2
3
1 2 3
6
從括號中的輸出可以看到,當我們第一次輸入1 2 3
和第一次輸入1 2
,調用reallyLongRunningComputation
,但是第二次輸入這些輸入時未調用。
我希望我離基地不遠,但是首先,您需要一種與過去的工作一起工作的方法。 最簡單的方法是使用foldM而不是forM。
import Control.Monad
import Data.Maybe
main = do
jobsToProcess <- fmap read getLine
foldM doJobAcc acc0 [1..jobsToProcess]
where
acc0 = --initial value of some type of accumulator, i.e. hash map
doJobAcc acc _ = do
[r, k] <- fmap (map read . words) getLine :: IO [Int]
case getFromHash acc (r,k) of
Nothing -> do
i <- doSomeReallyLongWorkingJob r k
return $ insertNew acc (r,k) i
Just i -> do
return acc
注意,我實際上並不使用該接口來放置和獲取哈希表鍵。 它實際上不必是哈希表,容器中的Data.Map可以工作。 甚至是一份清單(如果清單很小)。
攜帶哈希表的另一種方法是使用State轉換器monad。
我只是添加此答案,因為我覺得其他答案與原始問題有些出入,即在Main函數(在IO monad內部)中使用哈希表構造。
這是使用hashtables模塊的最小哈希表示例。 要使用cabal安裝模塊,只需使用
陰謀安裝哈希表
在此示例中,我們僅將一些值放入哈希表中,並使用查找打印從表中檢索到的值。
import qualified Data.HashTable.IO as H
main :: IO ()
main = do
t <- H.new :: IO (H.CuckooHashTable Int String)
H.insert t 22 "Hello world"
H.insert t 5 "No problem"
msg <- H.lookup t 5
print msg
注意,我們需要使用顯式類型注釋來指定我們希望使用的哈希表實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.