module Data.Lens.IxSet (ixLens) where
import Data.Data
import Data.IxSet
import Data.Lens.Common
{- |Focus on a key in an indexed set, much like with 'mapLens'.
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 using lenses and fix Simon's last name:
@
people\' = 'ixLens' (FirstName \"Simon\") '^%=' 'fmap' (lastName '^=' 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 = 'ixLens' (FirstName \"Simon\") '%=' 'fmap' (lastName '^=' LastName \"Peyton-Jones\")
@
Here's the missing boilerplate:
@
\{\-\# LANGUAGE DeriveDataTypeable \#\-\}
\{\-\# LANGUAGE TemplateHaskell \#\-\}
import Data.Data
import Data.IxSet
import Data.Lens
import Data.Lens.IxSet
import Data.Lens.Template
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