想象一个关联数字和单词的数组。一个单词只有一个数字,反之亦然。
dic = [0: 'food',
1: 'dinner',
2.5: 'breakfast',
...]
现在,我想访问dic[0]
并获取food
和something['food']
并获取0
。野外有任何可逆的哈希表吗?据我所知,只做副本可以解决这个问题。
答案 0 :(得分:0)
是的,这通常是通过组合两张地图来完成的。修改有点棘手,因为它们必须保持一对一的规则。
让我们从有限地图的类开始,以及containers
类型的几个示例实例:
{-# LANGUAGE
FunctionalDependencies
, FlexibleInstances
, UndecidableInstances
, GeneralizedNewtypeDeriving #-}
module Mappy where
import Prelude hiding (lookup)
-- Example base maps
import qualified Data.Map.Strict as M
import Data.Map (Map)
import qualified Data.IntMap.Strict as IM
import Data.IntMap (IntMap)
class Mappy k v m | m -> k v where
empty :: m
insert :: k -> v -> m -> m
delete :: k -> m -> m
lookup :: k -> m -> Maybe v
instance Ord k => Mappy k a (Map k a) where
empty = M.empty
insert = M.insert
delete = M.delete
lookup = M.lookup
instance Mappy Int a (IntMap a) where
empty = IM.empty
insert = IM.insert
delete = IM.delete
lookup = IM.lookup
现在我们可以为双向地图构建我们的类型:
data Bimap m n = Bimap !m !n
instance Show m => Show (Bimap m n) where
showsPrec p (Bimap m _) = showParen (p > 10) $
showString "Bimap " . showsPrec 11 m
invert :: Bimap m n -> Bimap n m
invert (Bimap m n) = Bimap n m
instance (Mappy k v kv, Mappy v k vk) => Mappy k v (Bimap kv vk) where
empty = Bimap empty empty
insert k v (Bimap kv vk)
| Just k' <- lookup v vk
= Bimap (insert k v $ delete k' kv) (insert v k vk)
| otherwise
= Bimap (insert k v kv) (insert v k vk)
delete k m@(Bimap kv vk)
| Just v <- lookup k kv
= Bimap (delete k kv) (delete v vk)
| otherwise
= m
lookup k (Bimap kv _) = lookup k kv
我们还可以定义一些包装器,以便更容易编写我们想要的地图类型。
newtype MapMap k v = MapMap (Bimap (Map k v) (Map v k)) deriving (Show, Mappy k v)
newtype IMM v = IMM (Bimap (IntMap v) (Map v Int)) deriving (Show, Mappy Int v)