alpha-1.0.1: src/My/Data/Relation.hs
{-# LANGUAGE NoMonomorphismRestriction #-}
module My.Data.Relation(Relation
,empty,singleton,fromList,toList
,inverse
,insert,delete
,member,notMember
,lookupRan,lookupDom,range,domain
,modifyRan,modifyDom,setRan,setDom
,filterDom,filterRan) where
import Control.Monad.State
import qualified Data.Map as M
import qualified Data.Set as S
import Data.Maybe
data Relation a b = Relation {
ranges :: M.Map a (S.Set b),
domains :: M.Map b (S.Set a)
}
deriving Show
empty = Relation M.empty M.empty
singleton a b = insert a b empty
fromList = foldr (uncurry insert) empty
toList r = [(a,b) | (a,bs) <- M.assocs (ranges r), b <- S.toList bs]
inverse (Relation a b) = Relation b a
insertVal a b m = M.alter (Just . S.insert b . fromMaybe S.empty) a m
deleteVal a b m = M.alter (mfilter (not . S.null) . fmap (S.delete b)) a m
insert a b (Relation ran dom) = Relation (insertVal a b ran) (insertVal b a dom)
delete a b (Relation ran dom) = Relation (deleteVal a b ran) (deleteVal b a dom)
member a b r = S.member b (lookupRan a r)
notMember a b = not . member a b
lookupRan a r = fromMaybe S.empty $ M.lookup a (ranges r)
range = S.unions . M.elems . ranges
lookupDom b = lookupRan b . inverse
domain = range . inverse
modifyRan f a r = r {
ranges = M.alter (const $ if S.null newRan then Nothing else Just newRan) a (ranges r),
domains = execState st (domains r)
}
where newRan = f oldRan ; oldRan = lookupRan a r
st = sequence_ [modify (deleteVal b a) | b <- S.toList $ oldRan S.\\ newRan]
>> sequence_ [modify (insertVal b a) | b <- S.toList $ newRan S.\\ oldRan]
modifyDom f b r = inverse (modifyRan f b (inverse r))
setRan a = flip modifyRan a . const
setDom b = flip modifyDom b . const
filterRan p r = inverse (filterDom p (inverse r))
filterDom p (Relation ran dom) = Relation (M.filterWithKey (const . p) ran) (M.map (S.filter p) dom)