[英]Haskell HashTable help rewrite using State monad
所以,这是我在Haskell中实现链式HashTable的笨拙代码。
{-# LANGUAGE FlexibleInstances #-}
import Data.Array(Array(..), array, bounds, elems, (//), (!))
import Data.List(foldl')
import Data.Char
import Control.Monad.State
class HashTranform a where
hashPrepare :: a -> Integer
instance HashTranform Integer where
hashPrepare = id
instance HashTranform String where
hashPrepare cs = fromIntegral (foldl' (flip ((+) . ord)) 0 cs)
divHashForSize :: (HashTranform a) => Integer -> a -> Integer
divHashForSize sz k = 1 + (hashPrepare k) `mod` sz
type Chain k v = [(k, v)]
chainWith :: (Eq k) => Chain k v -> (k, v) -> Chain k v
chainWith cs p@(k, v) = if (null after) then p:cs else before ++ p:(tail after)
where (before, after) = break ((== k) . fst) cs
chainWithout :: (Eq k) => Chain k v -> k -> Chain k v
chainWithout cs k = filter ((/= k) . fst) cs
data Hash k v = Hash {
hashFunc :: (k -> Integer)
, chainTable :: Array Integer (Chain k v)
}
--type HState k v = State (Hash k v)
instance (Show k, Show v) => Show (Hash k v) where
show = show . concat . elems . chainTable
type HashFuncForSize k = Integer -> k -> Integer
createHash :: HashFuncForSize k -> Integer -> Hash k v
createHash hs sz = Hash (hs sz) (array (1, sz) [(i, []) | i <- [1..sz]])
withSlot :: Hash k v -> k -> (Chain k v -> Chain k v) -> Hash k v
withSlot h k op
| rows < hashed = h
| otherwise = Hash hf (ht // [(hashed, op (ht!hashed))])
where hf = hashFunc h
ht = chainTable h
rows = snd (bounds ht)
hashed = hf k
insert' :: (Eq k) => Hash k v -> (k, v) -> Hash k v
insert' h p@(k, v) = withSlot h k (flip chainWith p)
delete' :: (Eq k) => Hash k v -> k -> Hash k v
delete' h k = withSlot h k (flip chainWithout k)
insert :: (Eq k) => Hash k v -> Chain k v -> Hash k v
insert src pairs = foldl' insert' src pairs
delete :: (Eq k) => Hash k v -> [k] -> Hash k v
delete src keys = foldl' delete' src keys
search :: (Eq k) => k -> Hash k v -> Maybe v
search k h
| rows < hashed = Nothing
| otherwise = k `lookup` (ht!hashed)
where hf = hashFunc h
ht = chainTable h
rows = snd (bounds ht)
hashed = hf k
问题是我不想要像这样的代码:
new = intHash `insert` [(1112, "uygfd"), (211, "catdied")]
new' = new `delete` [(1112, "uygfd")]
我相信它已经被State Monad以某种方式进行了修改,但是在阅读了在线教程后,我无法完全理解它是如何完成的。
那么你能告诉我如何实现至少插入,删除,搜索或其中任何一个来进行说明。
在一天结束时,你的“状态”将是Hash kv
。 我们将接口函数分为两组。 首先是“状态依赖”函数,如search k
,其类型为Hash kv -> _
(其中_
仅表示“某事”)。 其次是“状态更新”功能,如flip insert (k, v)
和flip delete ks
,其类型如Hash kv -> Hash kv
。
正如您所指出的,您已经可以通过手动传递Hash kv
参数来模拟“状态”。 State
monad只不过是为了让这更容易的类型魔术。
如果你看一下Control.Monad.State
你会看到modify :: (s -> s) -> State s ()
和gets :: (s -> a) -> State sa
。 这些函数将“状态更新”和“状态依赖”函数转换为“ State
monad动作”。 所以现在我们可以像这样编写一个State
monad组合动作
deleteIf :: (v -> Bool) -> k -> State (Hash k v) ()
deleteIf predicate k = do
v <- gets $ search k
case fmap predicate v of
Nothing -> return ()
Just False -> return ()
Just True -> modify $ flip delete [k]
然后我们可以一起排序更大的计算
computation = deleteIf (>0) 'a' >> deleteIf (>0) 'b'
然后通过“运行” State
monad来执行它们
runState computation (createHash f 100)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.