module Data.Lens.IxSet (ixLens) where
import Data.IxSet
import Data.Lens.Common
import Data.Typeable
-- |Focus on a key in an indexed set.
--
-- Given an 'IxSet' of people:
--
-- > people = fromList [ Person (FirstName "Edward A.") (LastName "Kmett")
-- > , Person (FirstName "Simon") (LastName "P. Jones")
-- > ]
--
-- We can now work with indices as lenses and fix Simon's last name:
--
-- > people' = lastName . ixLens (FirstName "Simon") ^= (LastName "Peyton-Jones") people
--
-- Perhaps more commonly you're working with an IxSet from inside a state monad such as with acid-state. In that case usage is even easier:
--
-- > changeLastName = lastName . ixLens (FirstName "Simon") %= LastName "Peyton-Jones"
--
-- Feels backwards? Lens composition uses 'Category' so we can flip it
-- around more intuitively using the composition arrows instead:
--
-- > changeLastName' = ixLens (FirstName "Simon") >>> lastName %= LastName "Peyton-Jones"
--
-- Here's the missing boilerplate:
--
-- > {-# LANGUAGE DeriveDataTypeable #-}
-- > {-# LANGUAGE TemplateHaskell #-}
-- >
-- > import Prelude hiding ((.))
-- > import Control.Category
-- > import Data.Data
-- >
-- > import Data.Lens
-- > import Data.Lens.Template
-- > import Data.IxSet
-- >
-- > data Person = Person { _firstName :: FirstName
-- > , _lastName :: LastName
-- > } deriving (Show, Eq, Ord, Data, Typeable)
-- >
-- > mkLens ''Person
-- >
-- > newtype FirstName = FirstName String
-- > deriving (Show, Eq, Ord, Data, Typeable)
-- >
-- > newtype LastName = LastName String
-- > deriving (Show, Eq, Ord, Data, Typeable)
-- >
-- > instance Indexable Person where
-- > empty = ixSet [ ixGen (Proxy :: Proxy FirstName)
-- > , ixGen (Proxy :: Proxy LastName)
-- > ]
ixLens :: (Indexable a, Typeable a, Typeable k, Ord a)
=> k -> Lens (IxSet a) (Maybe a)
ixLens k = lens get set
where
get = getOne . getEQ k
set (Just v) = updateIx k v
set Nothing = deleteIx k