{-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleContexts #-} {-# OPTIONS_HADDOCK prune #-} module Data.LensRef ( -- * Core -- ** References RefClass (..) , RefSimple , RefWriterOf , RefWriterSimple , MonadRefReader (..) , MonadRefWriter (..) -- ** Reference creation , MonadRefCreator (..) , Ref , RefReader , RefWriter -- ** Dynamic networks , MonadRegister (..) , RegionStatusChange (..) -- ** Other , MonadMemo (..) -- * Derived constructs , modRef , postponeModification -- , undoTr , EqRefClass (..) , EqRefSimple, EqRef , hasEffect , toEqRef , fromEqRef , newEqRef {- , CorrRef , corrRef , fromCorrRef , correction -} ) where import Control.Monad import Control.Monad.Identity import Control.Lens (Lens', set, united) -------------------------------- {- | Type class for references which can be joined and on which lenses can be applied. The join operation is 'join' from "Control.Monad": If @(r :: RefReaderSimple r (RefSimple r a))@ then @(join r :: RefSimple r a)@. This is possible because reference operations work with @(RefReaderSimple r (r a))@ instead of just @(r a)@. For more compact type signatures, @(RefReaderSimple r (r a))@ is called @(RefSimple r a)@. -} class (MonadRefWriter (RefWriterSimple r), MonadRefReader (RefReaderSimple r), RefReader (RefReaderSimple r) ~ RefReaderSimple r) => RefClass r where {- | unit reference -} unitRef :: RefSimple r () {- | Apply a lens on a reference. -} lensMap :: Lens' a b -> RefSimple r a -> RefSimple r b {- | Associated reference reader monad. @(RefReaderSimple m)@ is ismoroprhic to @('Reader' x)@ for some @x@. Laws which ensures this isomorphism (@(r :: RefReaderSimple m a)@ is arbitrary): prop> r >> return () = return () prop> liftM2 (,) r r = liftM (\a -> (a, a)) r See also -} type RefReaderSimple r :: * -> * {- | Reference read. -} readRefSimple :: RefSimple r a -> RefReaderSimple r a {- | Reference write. -} writeRefSimple :: RefSimple r a -> a -> RefWriterSimple r () data family RefWriterOf (m :: * -> *) :: * -> * {- | There are two associated types of a reference, 'RefReaderSimple' and 'RefWriterSimple' which determines each-other. This is implemented by putting only 'RefReaderSimple' into the 'RefClass' class and adding a @RefWriterOf@ data family outside of 'RefClass'. @RefWriterOf@ is hidden from the documentation because you never need it explicitly. -} type RefWriterSimple m = RefWriterOf (RefReaderSimple m) -- | Reference wrapped into a RefReaderSimple monad. See the documentation of 'RefClass'. type RefSimple r a = RefReaderSimple r (r a) infixr 8 `lensMap` -- | TODO class Monad m => MonadRefReader m where -- | Base reference associated to the reference reader monad type BaseRef m :: * -> * liftRefReader :: RefReader m a -> m a {- | @readRef@ === @liftRefReader . readRefSimple@ -} readRef :: (RefClass r, RefReader m ~ RefReaderSimple r) => RefSimple r a -> m a readRef = liftRefReader . readRefSimple -- | TODO type RefReader m = RefReaderSimple (BaseRef m) -- | TODO type RefWriter m = RefWriterSimple (BaseRef m) -- | TODO type Ref m a = RefSimple (BaseRef m) a -- | TODO class MonadRefReader m => MonadRefWriter m where liftRefWriter :: RefWriter m a -> m a {- | @writeRef r@ === @liftRefWriter . writeRefSimple r@ -} writeRef :: (RefClass r, RefReaderSimple r ~ RefReader m) => RefSimple r a -> a -> m () writeRef r = liftRefWriter . writeRefSimple r {- | Monad for reference creation. Reference creation is not a method of the 'RefClass' type class to make possible to create the same type of references in multiple monads. For basic usage examples, look into the source of @Data.LensRef.Test@. -} class (Monad m, RefClass (BaseRef m), MonadRefReader m, MonadMemo m) => MonadRefCreator m where {- | Reference creation by extending the state of an existing reference. Suppose that @r@ is a reference and @k@ is a lens. Law 1: @extRef@ applies @k@ on @r@ backwards, i.e. the result of @(extRef r k a0)@ should behaves exactly as @(lensMap k r)@. prop> (liftM (k .) $ extRef r k a0) = return r Law 2: @extRef@ does not change the value of @r@: prop> (extRef r k a0 >> readRef r) = readRef r Law 3: Proper initialization of newly defined reference with @a0@: prop> (extRef r k a0 >>= readRef) = (readRef r >>= set k a0) -} extRef :: Ref m b -> Lens' a b -> a -> m (Ref m a) {- | @newRef@ extends the state @s@ in an independent way. @newRef@ === @extRef unitRef united@ -} newRef :: a -> m (Ref m a) newRef = extRef unitRef united -- | TODO class Monad m => MonadMemo m where {- | Lazy monadic evaluation. In case of @y <- memoRead x@, invoking @y@ will invoke @x@ at most once. Laws: * @(memoRead x >> return ())@ === @return ()@ * @(memoRead x >>= id)@ === @x@ * @(memoRead x >>= \y -> liftM2 (,) y y)@ === @liftM (\a -> (a, a)) y@ * @(memoRead x >>= \y -> liftM3 (,) y y y)@ === @liftM (\a -> (a, a, a)) y@ * ... -} memoRead :: m a -> m (m a) {- memoWrite :: Eq b => (b -> m a) -> m (b -> m a) future :: (RefReader m a -> m a) -> m a -} -- | Monad for dynamic actions class (MonadRefCreator m, MonadRefWriter (Modifier m), MonadRefCreator (Modifier m), BaseRef (Modifier m) ~ BaseRef m, Monad (EffectM m), {- MonadRegister (Modifier m), -}EffectM (Modifier m) ~ EffectM m, Modifier (Modifier m) ~ Modifier m) => MonadRegister m where {- onChangeAcc :: Eq b => RefReader m b -> b -> (b -> c) -> (b -> b -> c -> m (c -> m c)) -> m (RefReader m c) -} onChange :: Eq a => RefReader m a -> (a -> m (m b)) -> m (RefReader m b) -- onChange r f = onChangeAcc r undefined undefined $ \b _ _ -> liftM const $ f b onChangeSimple :: Eq a => RefReader m a -> (a -> m b) -> m (RefReader m b) onChangeSimple r f = onChange r $ return . f onRegionStatusChange :: (RegionStatusChange -> m ()) -> m () type EffectM m :: * -> * liftEffectM :: EffectM m a -> m a type Modifier m :: * -> * liftToModifier :: m a -> Modifier m a registerCallback :: Functor f => f (Modifier m ()) -> m (f (EffectM m ())) -- unliftEffectM :: Functor f => f (m ()) -> m (f (EffectM m ())) -- registerCallback_ :: Functor f => f (Modifier m ()) -> m (f (m ())) -- registerCallback = registerCallback_ >=> unliftEffectM -- | TODO data RegionStatusChange = Kill | Block | Unblock deriving (Eq, Ord, Show) -------------- derived constructs -- | TODO postponeModification :: MonadRegister m => Modifier m () -> m () postponeModification = liftEffectM . runIdentity <=< registerCallback . Identity -- | @modRef r f@ === @readRef r >>= writeRef r . f@ modRef :: (MonadRefWriter m, RefClass r, RefReaderSimple r ~ RefReader m) => RefSimple r a -> (a -> a) -> m () r `modRef` f = readRef r >>= writeRef r . f {- | Reference with inherent equivalence. -} class RefClass r => EqRefClass r where valueIsChanging :: RefSimple r a -> RefReaderSimple r (a -> Bool) {- | @hasEffect r f@ returns @False@ iff @(modRef m f)@ === @(return ())@. @hasEffect@ is correct only if @toEqRef@ is applied on a pure reference (a reference which is a pure lens on the hidden state). @hasEffect@ makes defining auto-sensitive buttons easier, for example. -} hasEffect :: EqRefClass r => RefSimple r a -> (a -> a) -> RefReaderSimple r Bool hasEffect r f = do a <- readRef r ch <- valueIsChanging r return $ ch $ f a -- | TODO data EqRefCore r a = EqRefCore (r a) (a -> Bool{-changed-}) {- | RefClasss with inherent equivalence. @EqRefSimple r a@ === @RefReaderSimple r (exist b . Eq b => (Lens' b a, r b))@ As a reference, @(m :: EqRefSimple r a)@ behaves as @join $ liftM (uncurry lensMap) m@ -} type EqRefSimple r a = RefReaderSimple r (EqRefCore r a) -- | TODO type EqRef m a = EqRefSimple (BaseRef m) a {- | @EqRefSimple@ construction. -} toEqRef :: (RefClass r, Eq a) => RefSimple r a -> EqRefSimple r a toEqRef r = do a <- readRef r r_ <- r return $ EqRefCore r_ (/= a) -- | TODO newEqRef :: (MonadRefCreator m, Eq a) => a -> m (EqRef m a) newEqRef = liftM toEqRef . newRef {- | An @EqRefSimple@ is a normal reference if we forget about the equality. @fromEqRef m@ === @join $ liftM (uncurry lensMap) m@ -} fromEqRef :: RefClass r => EqRefSimple r a -> RefSimple r a fromEqRef m = m >>= \(EqRefCore r _) -> return r instance RefClass r => EqRefClass (EqRefCore r) where valueIsChanging m = do EqRefCore _r k <- m return k instance RefClass r => RefClass (EqRefCore r) where type (RefReaderSimple (EqRefCore r)) = RefReaderSimple r readRefSimple = readRef . fromEqRef writeRefSimple = writeRefSimple . fromEqRef lensMap l m = do a <- readRef m EqRefCore r k <- m lr <- lensMap l $ return r return $ EqRefCore lr $ \b -> k $ set l b a unitRef = toEqRef unitRef {- data CorrBaseRef r a = CorrBaseRef (r a) (a -> Maybe a{-corrected-}) type CorrRef r a = RefReaderSimple r (CorrBaseRef r a) instance RefClass r => RefClass (CorrBaseRef r) where type (RefReaderSimple (CorrBaseRef r)) = RefReaderSimple r readRef = readRef . fromCorrRef writeRefSimple = writeRefSimple . fromCorrRef lensMap l m = do a <- readRef m CorrBaseRef r k <- m lr <- lensMap l $ return r return $ CorrBaseRef lr $ \b -> fmap (^. l) $ k $ set l b a unitRef = corrRef (const Nothing) unitRef fromCorrRef :: RefClass r => CorrRef r a -> RefSimple r a fromCorrRef m = m >>= \(CorrBaseRef r _) -> return r corrRef :: RefClass r => (a -> Maybe a) -> RefSimple r a -> CorrRef r a corrRef f r = do r_ <- r return $ CorrBaseRef r_ f correction :: RefClass r => CorrRef r a -> RefReaderSimple r (a -> Maybe a) correction r = do CorrBaseRef _ f <- r return f -}