content: {-# LANGUAGE RankNTypes #-}
  module Fresnel.At
  ( -- * Updateable collections
    At(..)
  , Index
  , IxValue
    -- * Construction
  , atSet
  , atMap
  , ixAt
    -- * Elimination
  , sans
  ) where
  
  import           Control.Monad (guard)
  import qualified Data.HashMap.Internal.Strict as HashMap
  import qualified Data.HashSet as HashSet
  import           Data.Hashable
  import qualified Data.IntMap as IntMap
  import qualified Data.IntSet as IntSet
  import qualified Data.Map as Map
  import qualified Data.Set as Set
  import           Fresnel.Ixed
  import           Fresnel.Lens (Lens', lens)
  import           Fresnel.Maybe (_Just)
  import           Fresnel.Optional (Optional')
  import           Fresnel.Setter
  
  -- Updateable collections
  
  class Ixed c => At c where
    at :: Index c -> Lens' c (Maybe (IxValue c))
  
  instance At IntSet.IntSet where
    at = atSet IntSet.member IntSet.insert IntSet.delete
  
  instance At (IntMap.IntMap v) where
    at = atMap IntMap.lookup IntMap.insert IntMap.delete
  
  instance Ord k => At (Set.Set k) where
    at = atSet Set.member Set.insert Set.delete
  
  instance Ord k => At (Map.Map k v) where
    at = atMap Map.lookup Map.insert Map.delete
  
  instance Hashable k => At (HashSet.HashSet k) where
    at = atSet HashSet.member HashSet.insert HashSet.delete
  
  instance Hashable k => At (HashMap.HashMap k v) where
    at = atMap HashMap.lookup HashMap.insert HashMap.delete
  
  instance At (Maybe a) where
    at _ = lens id (const id)
  
  
  -- Construction
  
  atSet :: (Index c -> c -> Bool) -> (Index c -> c -> c) -> (Index c -> c -> c) -> Index c -> Lens' c (Maybe ())
  atSet member insert delete k = lens (guard . member k) (\ s -> maybe (delete k s) (const (insert k s)))
  
  atMap :: (Index c -> c -> Maybe (IxValue c)) -> (Index c -> IxValue c -> c -> c) -> (Index c -> c -> c) -> Index c -> Lens' c (Maybe (IxValue c))
  atMap lookup insert delete k = lens (lookup k) (\ m -> maybe (delete k m) (flip (insert k) m))
  
  ixAt :: At a => Index a -> Optional' a (IxValue a)
  ixAt i = at i . _Just
  
  
  -- Elimination
  
  sans :: At c => Index c -> c -> c
  sans k = at k .~ Nothing
  