-- | -- A map transformer that allows unknown keys to map to a default value. {-# LANGUAGE FlexibleContexts #-} module Web.Route.Invertible.Map.Default ( DefaultMap(..) , defaultingMap , defaultingValue , withDefaultMap , lookupDefault ) where import Control.Applicative ((<|>)) -- |A map that also provides a default value, for when a key is not found in the underlying map, parameterized over the type of the map. data DefaultMap m v = DefaultMap { defaultMap :: !(m v) , defaultValue :: !(Maybe v) } deriving (Eq, Show) instance Functor m => Functor (DefaultMap m) where fmap f (DefaultMap m d) = DefaultMap (fmap f m) (fmap f d) instance (Semigroup v, Semigroup (m v)) => Semigroup (DefaultMap m v) where DefaultMap m1 d1 <> DefaultMap m2 d2 = DefaultMap (m1 <> m2) (d1 <> d2) instance (Monoid v, Monoid (m v)) => Monoid (DefaultMap m v) where mempty = DefaultMap mempty Nothing mappend (DefaultMap m1 d1) (DefaultMap m2 d2) = DefaultMap (mappend m1 m2) (mappend d1 d2) -- |A simple map with no default value. defaultingMap :: m v -> DefaultMap m v defaultingMap m = DefaultMap m Nothing -- |A trivial map with only a default value. defaultingValue :: Monoid (m v) => v -> DefaultMap m v defaultingValue = DefaultMap mempty . Just -- |Transform the underlying map. withDefaultMap :: (m v -> n v) -> DefaultMap m v -> DefaultMap n v withDefaultMap f (DefaultMap m v) = DefaultMap (f m) v -- |Given a lookup function for the underlying map, return the default value instead if the value is not in the map. lookupDefault :: (m v -> Maybe v) -> DefaultMap m v -> Maybe v lookupDefault l (DefaultMap m d) = l m <|> d