module Data.Witness.WitnessDict where { import Data.Witness.Any; import Data.Witness.SimpleWitness; import Control.Monad.State; import Data.Maybe; -- | A dictionary that is heterogenous up to its simple witness type @w@. -- Witnesses are the keys of the dictionary, and the values they witness are the values of the dictionary. ; newtype WitnessDict w = MkWitnessDict [Any w]; -- | An empty dictionary. ; emptyWitnessDict :: WitnessDict w; emptyWitnessDict = MkWitnessDict[]; -- | Look up the first value in the dictionary that matches the given witness. ; witnessDictLookup :: (SimpleWitness w) => w a -> WitnessDict w -> Maybe a; witnessDictLookup wit (MkWitnessDict cells) = listToMaybe (mapMaybe (matchAny wit) cells); -- | Modify the first value in the dictionary that matches a particular witness. ; witnessDictModify :: (SimpleWitness w) => w a -> (a -> a) -> WitnessDict w -> WitnessDict w; witnessDictModify wit amap (MkWitnessDict cells) = MkWitnessDict (replaceFirst ((fmap ((MkAny wit) . amap)) . (matchAny wit)) cells) where { replaceFirst :: (a -> Maybe a) -> [a] -> [a]; replaceFirst ama (a:aa) = case ama a of { Just newa -> (newa:aa); _ -> a : (replaceFirst ama aa); }; replaceFirst _ _ = []; }; -- | Replace the first value in the dictionary that matches the witness ; witnessDictReplace :: (SimpleWitness w) => w a -> a -> WitnessDict w -> WitnessDict w; witnessDictReplace wit newa = witnessDictModify wit (const newa); -- | Add a witness and value as the first entry in the dictionary. ; witnessDictAdd :: w a -> a -> WitnessDict w -> WitnessDict w; witnessDictAdd wit a (MkWitnessDict cells) = MkWitnessDict ((MkAny wit a):cells); -- | Remove the first entry in the dictionary that matches the given witness. ; witnessDictRemove :: (SimpleWitness w) => w a -> WitnessDict w -> WitnessDict w; witnessDictRemove wit (MkWitnessDict cells) = MkWitnessDict (removeFirst (\(MkAny cwit _) -> isJust (matchWitness wit cwit)) cells) where { removeFirst :: (a -> Bool) -> [a] -> [a]; removeFirst p (a:as) | p a = as; removeFirst p (a:as) = a : (removeFirst p as); removeFirst _ _ = []; }; -- | Create a dictionary from a list of witness\/value pairs ; witnessDictFromList :: (SimpleWitness w) => [Any w] -> WitnessDict w; witnessDictFromList = MkWitnessDict; }