content: {-# LANGUAGE MultiParamTypeClasses #-}
  {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE KindSignatures #-}
  
  -- NOTE (asayers): I suppose this module doesn't really belong in
  -- euphoria... but I don't think it deserves its own package.
  module FRP.Euphoria.Internal.Maplike
      ( Maplike(..)
      , Lazy(..)
      , Strict(..)
      ) where
  
  import Data.Function
  import Data.Hashable (Hashable)
  import qualified Data.Map.Lazy       as ML
  import qualified Data.Map.Strict     as MS
  import qualified Data.HashMap.Lazy   as HML
  import qualified Data.HashMap.Strict as HMS
  import qualified Data.EnumMap.Lazy   as EML
  import qualified Data.EnumMap.Strict as EMS
  
  newtype Lazy c k v = Lazy (c k v)
  newtype Strict c k v = Strict (c k v)
  
  -- | A class for types with an API similar to that of "Data.Map".
  class Maplike c k where
      union        :: c k v -> c k v -> c k v
      intersection :: c k v -> c k v -> c k v
      difference   :: c k v -> c k v -> c k v
      empty        :: c k v
      lookup       :: k -> c k v -> Maybe v
      singleton    :: k -> v -> c k v
      singleton k v = insert k v empty
      insert :: k -> v -> c k v -> c k v
      insert k v m = singleton k v `union` m
      delete :: k -> c k v -> c k v
      delete k m =  m `difference` singleton k (error "bug")
      toList :: c k v -> [(k, v)]
      foldrWithKey :: (k -> v -> a -> a) -> a -> c k v -> a
  
  instance Ord k => Maplike (Lazy ML.Map) k where
      union        (Lazy x) (Lazy y) = Lazy $ ML.union x y
      intersection (Lazy x) (Lazy y) = Lazy $ ML.intersection x y
      difference   (Lazy x) (Lazy y) = Lazy $ x ML.\\ y
      empty                          = Lazy ML.empty
      lookup       k (Lazy x)        = ML.lookup k x
      singleton    k v               = Lazy $ ML.singleton k v
      insert       k v (Lazy x)      = Lazy $ ML.insert k v x
      delete       k (Lazy x)        = Lazy $ ML.delete k x
      toList       (Lazy x)          = ML.toList x
      foldrWithKey f a (Lazy x)      = ML.foldrWithKey f a x
  
  instance Ord k => Maplike (Strict MS.Map) k where
      union        (Strict x) (Strict y) = Strict $ MS.union x y
      intersection (Strict x) (Strict y) = Strict $ MS.intersection x y
      difference   (Strict x) (Strict y) = Strict $ x MS.\\ y
      empty                              = Strict MS.empty
      lookup       k (Strict x)          = MS.lookup k x
      singleton    k v                   = Strict $ MS.singleton k v
      insert       k v (Strict x)        = Strict $ MS.insert k v x
      delete       k (Strict x)          = Strict $ MS.delete k x
      toList       (Strict x)            = MS.toList x
      foldrWithKey f a (Strict x)        = MS.foldrWithKey f a x
  
  instance Enum k => Maplike (Lazy EML.EnumMap) k where
      union        (Lazy x) (Lazy y) = Lazy $ EML.union x y
      intersection (Lazy x) (Lazy y) = Lazy $ EML.intersection x y
      difference   (Lazy x) (Lazy y) = Lazy $ x EML.\\ y
      empty                          = Lazy EML.empty
      lookup       k (Lazy x)        = EML.lookup k x
      singleton    k v               = Lazy $ EML.singleton k v
      insert       k v (Lazy x)      = Lazy $ EML.insert k v x
      delete       k (Lazy x)        = Lazy $ EML.delete k x
      toList       (Lazy x)          = EML.toList x
      foldrWithKey f a (Lazy x)      = EML.foldrWithKey f a x
  
  instance Enum k => Maplike (Strict EMS.EnumMap) k where
      union        (Strict x) (Strict y) = Strict $ EMS.union x y
      intersection (Strict x) (Strict y) = Strict $ EMS.intersection x y
      difference   (Strict x) (Strict y) = Strict $ x EMS.\\ y
      empty                              = Strict EMS.empty
      lookup       k (Strict x)          = EMS.lookup k x
      singleton    k v                   = Strict $ EMS.singleton k v
      insert       k v (Strict x)        = Strict $ EMS.insert k v x
      delete       k (Strict x)          = Strict $ EMS.delete k x
      toList       (Strict x)            = EMS.toList x
      foldrWithKey f a (Strict x)        = EMS.foldrWithKey f a x
  
  instance (Eq k, Hashable k) => Maplike (Lazy HML.HashMap) k where
      union        (Lazy x) (Lazy y) = Lazy $ HML.union x y
      intersection (Lazy x) (Lazy y) = Lazy $ HML.intersection x y
      difference   (Lazy x) (Lazy y) = Lazy $ HML.difference x y
      empty                          = Lazy HML.empty
      lookup       k (Lazy x)        = HML.lookup k x
      singleton    k v               = Lazy $ HML.singleton k v
      insert       k v (Lazy x)      = Lazy $ HML.insert k v x
      delete       k (Lazy x)        = Lazy $ HML.delete k x
      toList       (Lazy x)          = HML.toList x
      foldrWithKey f a (Lazy x)      = HML.foldrWithKey f a x
  
  instance (Eq k, Hashable k) => Maplike (Strict HMS.HashMap) k where
      union        (Strict x) (Strict y) = Strict $ HMS.union x y
      intersection (Strict x) (Strict y) = Strict $ HMS.intersection x y
      difference   (Strict x) (Strict y) = Strict $ HMS.difference x y
      empty                              = Strict HMS.empty
      lookup       k (Strict x)          = HMS.lookup k x
      singleton    k v                   = Strict $ HMS.singleton k v
      insert       k v (Strict x)        = Strict $ HMS.insert k v x
      delete       k (Strict x)          = Strict $ HMS.delete k x
      toList       (Strict x)            = HMS.toList x
      foldrWithKey f a (Strict x)        = HMS.foldrWithKey f a x
  