{-| Minimal redefine + re-export of a lens package, fclabels -} {-# LANGUAGE TypeOperators, NoMonomorphismRestriction #-} module CHR.Data.Lens.FCLabels ( (:->) , Lens -- * Access , (^*) , (^.) , (^=) , (^$=) , getL , (=.) , (=:) , (=$:) , modifyAndGet, (=$^:), modL , getl -- * Misc , focus , mkLabel -- * Tuple accessors , fstl , sndl , fst3l , snd3l , trd3l -- * Wrappers , isoMb , isoMbWithDefault ) where import Prelude hiding ((.), id) import qualified Control.Monad.State as MS import Control.Monad.Trans import Control.Category import Data.Label hiding (Lens, lens) import qualified Data.Label.Base as L import qualified Data.Label as L import Data.Label.Monadic((=:), (=.), modifyAndGet) import qualified Data.Label.Monadic as M import qualified Data.Label.Partial as P import CHR.Utils -- * Textual alias for (:->), avoiding TypeOperators type Lens a b = a :-> b -- * Operator interface for composition infixl 9 ^* -- | composition with a flipped reading (^*) :: (a :-> b) -> (b :-> c) -> (a :-> c) f1 ^* f2 = f2 . f1 {-# INLINE (^*) #-} -- * Operator interface for functional part (occasionally similar to Data.Lens) infixl 8 ^. -- | functional getter, which acts like a field accessor (^.) :: a -> (a :-> b) -> b a ^. f = get f a {-# INLINE (^.) #-} -- | Alias for 'get' to avoid conflict with state get; not happy choice because of 'getl' getL :: (f :-> a) -> f -> a getL = get {-# INLINE getL #-} infixr 4 ^= -- | functional setter, which acts like a field assigner (^=) :: (a :-> b) -> b -> a -> a (^=) = set {-# INLINE (^=) #-} infixr 4 ^$= -- | functional modify (^$=) :: (a :-> b) -> (b -> b) -> a -> a (^$=) = modify {-# INLINE (^$=) #-} -- * Operator interface for monadic part (occasionally similar to Data.Lens) infixr 4 =$^: -- | monadic modify & set & get (=$^:), modL :: MS.MonadState f m => (f :-> o) -> (o -> (a,o)) -> m a (=$^:) = M.modifyAndGet {-# INLINE (=$^:) #-} modL = M.modifyAndGet {-# INLINE modL #-} infixr 4 =$: -- | monadic modify & set (=$:) :: MS.MonadState f m => (f :-> o) -> (o -> o) -> m () (=$:) = M.modify {-# INLINE (=$:) #-} -- | Zoom state in on substructure. This regretfully does not really work, because of MonadState fundep. focus :: (MS.MonadState a m, MS.MonadState b m) => (a :-> b) -> m c -> m c focus f m = do a <- MS.get (b,c) <- do {MS.put (get f a) ; c <- m ; b <- MS.get ; return (b,c)} MS.put $ set f b a return c {- (Lens f) (StateT g) = StateT $ \a -> case f a of StoreT (Identity h) b -> liftM (second h) (g b) -} -- | Alias for 'gets' avoiding conflict with MonadState getl :: MS.MonadState f m => (f :-> o) -> m o getl = M.gets {-# INLINE getl #-} -- * Tuple fstl = L.fst {-# INLINE fstl #-} sndl = L.snd {-# INLINE sndl #-} fst3l = L.fst3 {-# INLINE fst3l #-} snd3l = L.snd3 {-# INLINE snd3l #-} trd3l = L.trd3 {-# INLINE trd3l #-} -- * Wrappers -- | Wrapper around a Maybe with a default in case of Nothing isoMbWithDefault :: o -> (f :-> Maybe o) -> (f :-> o) isoMbWithDefault dflt f = iso (Iso (maybe dflt id) (Just)) . f -- | Wrapper around a Maybe with an embedded panic in case of Nothing, with a panic message isoMb :: String -> (f :-> Maybe o) -> (f :-> o) isoMb msg f = iso (Iso (panicJust msg) (Just)) . f