module Control.Lens
(
Lens
, LensFamily
, Getter
, Setter
, SetterFamily
, MultiLens
, MultiLensFamily
, makeLenses
, makeLensesBy
, makeLensesFor
, lens
, iso
, clone
, getting
, gettingMany
, setting
, reading
, modifying
, writing
, (^.), (^$)
, (^%=), (^=), (^+=), (^-=), (^*=), (^/=), (^||=), (^&&=)
, access
, Focus(..)
, (%=), (~=), (%%=), (+=), (-=), (*=), (//=), (||=), (&&=)
, fstL
, sndL
, keyL
, intKeyL
, memberL
, intMemberL
, identityL
, atL
, folded
, mapOf
, foldMapOf
, foldrOf
, foldOf
, toListOf
, anyOf, allOf
, andOf, orOf
, productOf, sumOf
, traverseOf_
, forOf_
, sequenceAOf_
, mapMOf_
, forMOf_
, sequenceOf_
, asumOf, msumOf
, concatMapOf
, concatOf
, elemOf
, notElemOf
, constML
, keyML
, intKeyML
, headML
, tailML
, leftML
, elementML
, traverseOf
, mapMOf
, sequenceAOf
, sequenceOf
, IndexedStore
, Focusing
, Traversal
) where
import Control.Applicative as Applicative
import Control.Monad (liftM, MonadPlus(..))
import Control.Monad.State.Class
import qualified Control.Monad.Trans.State.Lazy as Lazy
import qualified Control.Monad.Trans.State.Strict as Strict
import Control.Monad.Trans.Reader
import Data.Char (toLower)
import Data.Foldable as Foldable
import Data.Functor.Identity
import Data.IntMap as IntMap
import Data.IntSet as IntSet
import Data.Map as Map
import Data.Monoid
import Data.Set as Set
import Data.Traversable
import Language.Haskell.TH
infixl 8 ^.
infixr 4 ^%=, ^=, ^+=, ^*=, ^-=, ^/=, ^&&=, ^||=
infix 4 ~=, %=, %%=, +=, -=, *=, //=, &&=, ||=
infixr 0 ^$
type Lens a b = forall f. Functor f => (b -> f b) -> a -> f a
type LensFamily a b c d = forall f. Functor f => (c -> f d) -> a -> f b
type Getter a b = forall x y z. (b -> Const z x) -> a -> Const z y
type Setter a b = (b -> Identity b) -> a -> Identity a
type SetterFamily a b c d = (c -> Identity d) -> a -> Identity b
type MultiGetter a c = forall x y m. Monoid m => (c -> Const m x) -> a -> Const m y
type MultiLens a b = forall f. Applicative f => (b -> f b) -> a -> f a
type MultiLensFamily a b c d = forall f. Applicative f => (c -> f d) -> a -> f b
lens :: Functor f => (a -> c) -> (d -> a -> b) -> (c -> f d) -> a -> f b
lens ac dab cfd a = (`dab` a) <$> cfd (ac a)
iso :: Functor f => (a -> c) -> (d -> b) -> (c -> f d) -> a -> f b
iso f g h a = g <$> h (f a )
getting :: (a -> b) -> Getter a b
getting f g a = Const (getConst (g (f a)))
gettingMany :: Foldable f => (a -> f b) -> MultiGetter a b
gettingMany f g a = Const (foldMap (getConst . g) (f a))
setting :: ((c -> d) -> a -> b) -> SetterFamily a b c d
setting f g a = Identity (f (runIdentity . g) a)
reading :: ((c -> Const c d) -> a -> Const c b) -> a -> c
reading l a = getConst (l Const a)
mapOf, modifying :: ((c -> Identity d) -> a -> Identity b) -> (c -> d) -> a -> b
mapOf l f a = runIdentity (l (Identity . f) a)
modifying = mapOf
writing :: ((c -> Identity d) -> a -> Identity b) -> d -> a -> b
writing l d a = runIdentity (l (\_ -> Identity d) a)
(^$) :: ((c -> Const c d) -> a -> Const c b) -> a -> c
l ^$ a = getConst (l Const a)
(^.) :: a -> ((c -> Const c d) -> a -> Const c b) -> c
a ^. l = getConst (l Const a)
(^%=) :: ((c -> Identity d) -> a -> Identity b) -> (c -> d) -> a -> b
l ^%= f = runIdentity . l (Identity . f)
(^=) :: ((c -> Identity d) -> a -> Identity b) -> d -> a -> b
l ^= v = runIdentity . l (Identity . const v)
(^+=) :: Num c => ((c -> Identity c) -> a -> Identity a) -> c -> a -> a
l ^+= n = mapOf l (+ n)
(^*=) :: Num c => ((c -> Identity c) -> a -> Identity a) -> c -> a -> a
l ^-= n = mapOf l (`subtract` n)
(^-=) :: Num c => ((c -> Identity c) -> a -> Identity a) -> c -> a -> a
l ^*= n = mapOf l (* n)
(^/=) :: Fractional c => ((c -> Identity c) -> a -> Identity a) -> c -> a -> a
l ^/= n = mapOf l (/ n)
(^||=):: ((Bool -> Identity Bool) -> a -> Identity a) -> Bool -> a -> a
l ^||= n = mapOf l (|| n)
(^&&=) :: ((Bool -> Identity Bool) -> a -> Identity a) -> Bool -> a -> a
l ^&&= n = mapOf l (&& n)
data IndexedStore c d a = IndexedStore (d -> a) c
instance Functor (IndexedStore c d) where
fmap f (IndexedStore g c) = IndexedStore (f . g) c
clone :: Functor f => ((c -> IndexedStore c d d) -> a -> IndexedStore c d b) -> (c -> f d) -> a -> f b
clone f cfd a = case f (IndexedStore id) a of
IndexedStore db c -> db <$> cfd c
fstL :: LensFamily (a,c) (b,c) a b
fstL f (a,c) = (\b -> (b,c)) <$> f a
sndL :: LensFamily (c,a) (c,b) a b
sndL f (c,a) = (,) c <$> f a
keyL :: Ord k => k -> Lens (Map k v) (Maybe v)
keyL k f m = go <$> f (Map.lookup k m) where
go Nothing = Map.delete k m
go (Just v') = Map.insert k v' m
intKeyL :: Int -> Lens (IntMap v) (Maybe v)
intKeyL k f m = go <$> f (IntMap.lookup k m) where
go Nothing = IntMap.delete k m
go (Just v') = IntMap.insert k v' m
memberL :: Ord k => k -> Lens (Set k) Bool
memberL k f s = go <$> f (Set.member k s) where
go False = Set.delete k s
go True = Set.insert k s
intMemberL :: Int -> Lens IntSet Bool
intMemberL k f s = go <$> f (IntSet.member k s) where
go False = IntSet.delete k s
go True = IntSet.insert k s
identityL :: LensFamily (Identity a) (Identity b) a b
identityL f (Identity a) = Identity <$> f a
atL :: Eq e => e -> Lens (e -> a) a
atL e afa ea = go <$> afa a where
a = ea e
go a' e' | e == e' = a'
| otherwise = a
access :: MonadState a m => ((c -> Const c d) -> a -> Const c b) -> m c
access l = gets (^. l)
newtype Focusing m c a = Focusing { unfocusing :: m (c, a) }
instance Monad m => Functor (Focusing m c) where
fmap f (Focusing m) = Focusing (liftM (fmap f) m)
instance (Monad m, Monoid c) => Applicative (Focusing m c) where
pure a = Focusing (return (mempty, a))
Focusing mf <*> Focusing ma = Focusing $ do
(c, f) <- mf
(d, a) <- ma
return (mappend c d, f a)
class Focus st where
focus :: Monad m => ((b -> Focusing m c b) -> a -> Focusing m c a) -> st b m c -> st a m c
instance Focus Strict.StateT where
focus l (Strict.StateT m) = Strict.StateT $ \a -> unfocusing (l (Focusing . m) a)
instance Focus Lazy.StateT where
focus l (Lazy.StateT m) = Lazy.StateT $ \a -> unfocusing (l (Focusing . m) a)
instance Focus ReaderT where
focus l (ReaderT m) = ReaderT $ \a -> liftM undefined $ unfocusing $ l (\b -> Focusing $ (\c -> (c,b)) `liftM` m b) a
(~=) :: MonadState a m => Setter a b -> b -> m ()
l ~= b = modify (l ^= b)
(%=) :: MonadState a m => Setter a b -> (b -> b) -> m ()
l %= f = modify (l ^%= f)
(%%=) :: MonadState a m => ((b -> (c,b)) -> a -> (c,a)) -> (b -> (c, b)) -> m c
l %%= f = state (l f)
(+=) :: (MonadState a m, Num b) => Setter a b -> b -> m ()
l += b = modify $ l ^+= b
(-=) :: (MonadState a m, Num b) => Setter a b -> b -> m ()
l -= b = modify $ l ^-= b
(*=) :: (MonadState a m, Num b) => Setter a b -> b -> m ()
l *= b = modify $ l ^*= b
(//=) :: (MonadState a m, Fractional b) => Setter a b -> b -> m ()
l //= b = modify $ l ^/= b
(&&=):: MonadState a m => Setter a Bool -> Bool -> m ()
l &&= b = modify $ l ^&&= b
(||=) :: MonadState a m => Setter a Bool -> Bool -> m ()
l ||= b = modify $ l ^||= b
foldMapOf :: Monoid m => ((c -> Const m d) -> a -> Const m b) -> (c -> m) -> a -> m
foldMapOf l f = getConst . l (Const . f)
foldOf :: Monoid m => ((m -> Const m n) -> a -> Const m b) -> a -> m
foldOf l = getConst . l Const
foldrOf :: ((c -> Const (Endo e) d) -> a -> Const (Endo e) b) -> (c -> e -> e) -> e -> a -> e
foldrOf l f z t = appEndo (foldMapOf l (Endo . f) t) z
toListOf :: ((c -> Const [c] d) -> a -> Const [c] b) -> a -> [c]
toListOf l = foldMapOf l return
andOf :: ((Bool -> Const All d) -> a -> Const All b) -> a -> Bool
andOf l = getAll . foldMapOf l All
orOf :: ((Bool -> Const Any d) -> a -> Const Any b) -> a -> Bool
orOf l = getAny . foldMapOf l Any
anyOf :: ((c -> Const Any d) -> a -> Const Any b) -> (c -> Bool) -> a -> Bool
anyOf l f = getAny . foldMapOf l (Any . f)
allOf :: ((c -> Const All d) -> a -> Const All b) -> (c -> Bool) -> a -> Bool
allOf l f = getAll . foldMapOf l (All . f)
productOf :: Num c => ((c -> Const (Product c) d) -> a -> Const (Product c) b) -> a -> c
productOf l = getProduct . foldMapOf l Product
sumOf :: Num c => ((c -> Const (Sum c) d) -> a -> Const (Sum c) b) -> a -> c
sumOf l = getSum . foldMapOf l Sum
traverseOf_ :: Applicative f => ((c -> Const (Traversal f) d) -> a -> Const (Traversal f) b) -> (c -> f e) -> a -> f ()
traverseOf_ l f = getTraversal . foldMapOf l (Traversal . (() <$) . f)
forOf_ :: Applicative f => ((c -> Const (Traversal f) d) -> a -> Const (Traversal f) b) -> a -> (c -> f e) -> f ()
forOf_ l a f = traverseOf_ l f a
sequenceAOf_ :: Applicative f => ((f () -> Const (Traversal f) d) -> a -> Const (Traversal f) e) -> a -> f ()
sequenceAOf_ l = getTraversal . foldMapOf l (Traversal . (() <$))
mapMOf_ :: Monad m => ((c -> Const (Traversal (WrappedMonad m)) d) -> a -> Const (Traversal (WrappedMonad m)) b) -> (c -> m e) -> a -> m ()
mapMOf_ l f = unwrapMonad . traverseOf_ l (WrapMonad . f)
forMOf_ :: Monad m => ((c -> Const (Traversal (WrappedMonad m)) d) -> a -> Const (Traversal (WrappedMonad m)) b) -> a -> (c -> m e) -> m ()
forMOf_ l a f = mapMOf_ l f a
sequenceOf_ :: Monad m => ((m c -> Const (Traversal (WrappedMonad m)) d) -> a -> Const (Traversal (WrappedMonad m)) b) -> a -> m ()
sequenceOf_ l = unwrapMonad . traverseOf_ l WrapMonad
asumOf :: Alternative f => ((f c -> Const (Endo (f c)) d) -> a -> Const (Endo (f c)) b) -> a -> f c
asumOf l = foldrOf l (<|>) Applicative.empty
msumOf :: MonadPlus m => ((m c -> Const (Endo (m c)) d) -> a -> Const (Endo (m c)) b) -> a -> m c
msumOf l = foldrOf l mplus mzero
elemOf :: Eq c => ((c -> Const Any d) -> a -> Const Any b) -> c -> a -> Bool
elemOf l = anyOf l . (==)
notElemOf :: Eq c => ((c -> Const Any d) -> a -> Const Any b) -> c -> a -> Bool
notElemOf l c = not . elemOf l c
concatMapOf :: ((c -> Const [e] d) -> a -> Const [e] b) -> (c -> [e]) -> a -> [e]
concatMapOf l ces a = getConst (l (Const . ces) a)
concatOf :: (([e] -> Const [e] d) -> a -> Const [e] b) -> a -> [e]
concatOf = reading
traverseOf :: Applicative f => ((c -> f d) -> a -> f b) -> (c -> f d) -> a -> f b
traverseOf = id
mapMOf :: Monad m => ((c -> WrappedMonad m d) -> a -> WrappedMonad m b) -> (c -> m d) -> a -> m b
mapMOf l cmd a = unwrapMonad (l (WrapMonad . cmd) a)
sequenceAOf :: Applicative f => ((f b -> f (f b)) -> a -> f b) -> a -> f b
sequenceAOf l = l pure
sequenceOf :: Monad m => ((m b -> WrappedMonad m (m b)) -> a -> WrappedMonad m b) -> a -> m b
sequenceOf l = unwrapMonad . l pure
folded :: Foldable f => MultiGetter (f a) a
folded = gettingMany id
constML :: Applicative f => (c -> f d) -> a -> f a
constML = const pure
headML :: Applicative f => (a -> f a) -> [a] -> f [a]
headML _ [] = pure []
headML f (a:as) = (:as) <$> f a
tailML :: Applicative f => ([a] -> f [a]) -> [a] -> f [a]
tailML _ [] = pure []
tailML f (a:as) = (a:) <$> f as
leftML :: Applicative f => (a -> f b) -> Either a c -> f (Either b c)
leftML f (Left a) = Left <$> f a
leftML _ (Right c) = pure $ Right c
keyML :: (Applicative f, Ord k) => k -> (v -> f v) -> Map k v -> f (Map k v)
keyML k = keyL k . traverse
intKeyML :: Applicative f => Int -> (v -> f v) -> IntMap v -> f (IntMap v)
intKeyML k = intKeyL k . traverse
elementML :: (Applicative f, Traversable t) => Int -> (a -> f a) -> t a -> f (t a)
elementML j f ta = fst (runSA (traverse go ta) 0) where
go a = SA $ \i -> (if i == j then f a else pure a, i + 1)
newtype SA f a = SA { runSA :: Int -> (f a, Int) }
instance Functor f => Functor (SA f) where
fmap f (SA m) = SA $ \i -> case m i of
(fa, j) -> (fmap f fa, j)
instance Applicative f => Applicative (SA f) where
pure a = SA (\i -> (pure a, i))
SA mf <*> SA ma = SA $ \i -> case mf i of
(ff, j) -> case ma j of
(fa, k) -> (ff <*> fa, k)
newtype Traversal f = Traversal { getTraversal :: f () }
instance Applicative f => Monoid (Traversal f) where
mempty = Traversal (pure ())
Traversal ma `mappend` Traversal mb = Traversal (ma *> mb)
defaultNameTransform :: String -> Maybe String
defaultNameTransform ('_':c:rest) = Just $ toLower c : rest
defaultNameTransform _ = Nothing
type LensTypeInfo = (Name, [TyVarBndr])
type ConstructorFieldInfo = (Name, Strict, Type)
makeLensesBy ::
(String -> Maybe String)
-> Name -> Q [Dec]
makeLensesBy nameTransform datatype = do
typeInfo <- extractLensTypeInfo datatype
let derive1 = deriveLens nameTransform typeInfo
constructorFields <- extractConstructorFields datatype
Prelude.concat <$> Prelude.mapM derive1 constructorFields
extractLensTypeInfo :: Name -> Q LensTypeInfo
extractLensTypeInfo datatype = do
let datatypeStr = nameBase datatype
i <- reify datatype
return $ case i of
TyConI (DataD _ n ts _ _) -> (n, ts)
TyConI (NewtypeD _ n ts _ _) -> (n, ts)
_ -> error $ "Can't derive Lens for: " ++ datatypeStr ++ ", type name required."
extractConstructorFields :: Name -> Q [ConstructorFieldInfo]
extractConstructorFields datatype = do
let datatypeStr = nameBase datatype
i <- reify datatype
return $ case i of
TyConI (DataD _ _ _ [RecC _ fs] _) -> fs
TyConI (NewtypeD _ _ _ (RecC _ fs) _) -> fs
TyConI (DataD _ _ _ [_] _) -> error $ "Can't derive Lens without record selectors: " ++ datatypeStr
TyConI NewtypeD{} -> error $ "Can't derive Lens without record selectors: " ++ datatypeStr
TyConI TySynD{} -> error $ "Can't derive Lens for type synonym: " ++ datatypeStr
TyConI DataD{} -> error $ "Can't derive Lens for tagged union: " ++ datatypeStr
_ -> error $ "Can't derive Lens for: " ++ datatypeStr ++ ", type name required."
deriveLens :: (String -> Maybe String)
-> LensTypeInfo
-> ConstructorFieldInfo
-> Q [Dec]
deriveLens nameTransform ty field = case nameTransform (nameBase fieldName) of
Nothing -> return []
Just lensNameStr -> do
body <- deriveLensBody (mkName lensNameStr) fieldName
return [body]
where
(fieldName, _fieldStrict, _fieldType) = field
(_tyName, _tyVars) = ty
deriveLensBody :: Name -> Name -> Q Dec
deriveLensBody lensName fieldName = funD lensName [defLine]
where
a = mkName "a"
f = mkName "f"
defLine = clause pats (normalB body) []
pats = [varP f, varP a]
body = [| (\x -> $(record a fieldName [|x|]))
`fmap` $(appE (varE f) (appE (varE fieldName) (varE a)))
|]
record rec fld val = val >>= \v -> recUpdE (varE rec) [return (fld, v)]
makeLenses :: Name -> Q [Dec]
makeLenses = makeLensesBy defaultNameTransform
makeLensesFor :: [(String, String)] -> Name -> Q [Dec]
makeLensesFor fields = makeLensesBy (`Prelude.lookup` fields)