2{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FunctionalDependencies #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6{-# LANGUAGE LambdaCase #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE RecursiveDo #-}
9{-# LANGUAGE ScopedTypeVariables #-}
10{-# LANGUAGE TypeFamilies #-}
11{-# LANGUAGE UndecidableInstances #-}
12module Reflex.DynamicWriter where
14import Control.Monad.Exception
15import Control.Monad.IO.Class
16import Control.Monad.Reader
17import Control.Monad.Ref
18import Control.Monad.State.Strict
19import Data.Dependent.Map (DMap)
20import Data.Functor.Compose
21import Data.Functor.Misc
23import qualified Data.Map as Map
26import Reflex.Deletable.Class
27import Reflex.PerformEvent.Class
28import Reflex.PostBuild.Class
29import Reflex.Host.Class
31instance MonadTrans (DynamicWriterT t w) where
32 lift = DynamicWriterT . lift
35 PatchMap :: Ord k => Map k (Maybe v) -> PatchMap (Map k v)
37instance Patch PatchMap where
38 apply (PatchMap p) old = Just $! insertions `Map.union` (old `Map.difference` deletions) --TODO: return Nothing sometimes --Note: the strict application here is critical to ensuring that incremental merges don't hold onto all their prerequisite events forever; can we make this more robust?
39 where insertions = Map.mapMaybeWithKey (const id) p
40 deletions = Map.mapMaybeWithKey (const nothingToJust) p
45instance Ord k => Semigroup (PatchMap (Map k v)) where
46 PatchMap a <> PatchMap b = PatchMap $ a `mappend` b --TODO: Add a semigroup instance for Map
47 -- PatchMap is idempotent, so stimes n is id for every n
48#if MIN_VERSION_semigroups(0,17,0)
49 stimes = stimesIdempotentMonoid
51 times1p n x = case compare n 0 of
52 LT -> error "stimesIdempotentMonoid: negative multiplier"
57instance Ord k => Monoid (PatchMap (Map k v)) where
58 mempty = PatchMap mempty
61mconcatIncremental :: (Reflex t, MonadHold t m, MonadFix m, Monoid v) => Map k v -> Event t (PatchMap (Map k v)) -> m (Dynamic t v)
62mconcatIncremental m0 e = do
63 d <- foldDynMaybe apply m0 e
64 return $ fmap (mconcat . Map.elems) d
66mapIncrementalMapValuesWithKey :: Reflex t => (k -> v -> v') -> Incremental t PatchMap (Map k v) -> Incremental t PatchMap (Map k v')
67mapIncrementalMapValuesWithKey f = unsafeMapIncremental (Map.mapWithKey f) $ \(PatchMap m) -> PatchMap $ Map.mapWithKey (\k mv -> fmap (f k) mv) m
69mapIncrementalMapValues :: Reflex t => (v -> v') -> Incremental t PatchMap (Map k v) -> Incremental t PatchMap (Map k v')
70mapIncrementalMapValues f = mapIncrementalMapValuesWithKey $ const f
72unsafeMapIncremental :: (Reflex t, Patch p, Patch p') => (a -> a') -> (p a -> p' a') -> Incremental t p a -> Incremental t p' a'
73unsafeMapIncremental f g a = unsafeBuildIncremental (fmap f $ sample $ currentIncremental a) $ g <$> updatedIncremental a
75incrementalExtractFunctorDMap :: Reflex t => Incremental t PatchMap (Map k (f v)) -> Incremental t PatchDMap (DMap (Const2 k v) f)
76incrementalExtractFunctorDMap = unsafeMapIncremental mapWithFunctorToDMap $ \(PatchMap m) -> PatchDMap $ mapWithFunctorToDMap $ fmap Compose m
78mergeIncrementalMap :: (Reflex t, Ord k) => Incremental t PatchMap (Map k (Event t v)) -> Event t (Map k v)
79mergeIncrementalMap = fmap dmapToMap . mergeIncremental . incrementalExtractFunctorDMap
81holdIncrementalReplaceableMap :: forall t k v m. (MonadFix m, MonadHold t m, Reflex t, Ord k) => Map k (Replaceable t v) -> Event t (PatchMap (Map k (Replaceable t v))) -> m (Incremental t PatchMap (Map k v))
82holdIncrementalReplaceableMap m0 m' = do
83 rec vals <- holdIncremental m0 $ m' <> valChanges
84 let valChanges = fmap PatchMap $ mergeIncrementalMap $ mapIncrementalMapValues _replaceable_modify vals
85 return $ mapIncrementalMapValues _replaceable_value vals
87mergeDynIncremental :: (Reflex t, Ord k) => Incremental t PatchMap (Map k (Dynamic t v)) -> Incremental t PatchMap (Map k v)
88mergeDynIncremental a = unsafeBuildIncremental (mapM (sample . current) =<< sample (currentIncremental a)) $ addedAndRemovedValues <> changedValues
89 where changedValues = fmap (PatchMap . fmap Just) $ mergeIncrementalMap $ mapIncrementalMapValues updated a
90 addedAndRemovedValues = flip pushAlways (updatedIncremental a) $ \(PatchMap m) -> PatchMap <$> mapM (mapM (sample . current)) m
92data Replaceable t w = Replaceable
93 { _replaceable_value :: w
94 , _replaceable_modify :: Event t (Maybe (Replaceable t w)) -- "Please delete" is represented with an event of Nothing; all subsequent events will be ignored
97type DynamicWriterAccumulator t w = [Replaceable t (Dynamic t w)]
99newtype DynamicWriterT t w m a = DynamicWriterT { unDynamicWriterT :: StateT (DynamicWriterAccumulator t w) m a } deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadHold t, MonadSample t, MonadAsyncException, MonadException) -- The list is kept in reverse order
101instance MonadRef m => MonadRef (DynamicWriterT t w m) where
102 type Ref (DynamicWriterT t w m) = Ref m
103 newRef = lift . newRef
104 readRef = lift . readRef
105 writeRef r = lift . writeRef r
107instance MonadAtomicRef m => MonadAtomicRef (DynamicWriterT t w m) where
108 atomicModifyRef r = lift . atomicModifyRef r
110instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (DynamicWriterT t w m) where
111 newEventWithTrigger = lift . newEventWithTrigger
112 newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
114runDynamicWriterTInternal :: DynamicWriterT t w m a -> m (a, DynamicWriterAccumulator t w)
115runDynamicWriterTInternal (DynamicWriterT a) = runStateT a []
117mconcatIncrementalReplaceableDynMap :: forall m t k v. (MonadFix m, MonadHold t m, Reflex t, Monoid v, Ord k) => Map k (Replaceable t (Dynamic t v)) -> Event t (PatchMap (Map k (Replaceable t (Dynamic t v)))) -> Event t () -> m (Replaceable t (Dynamic t v))
118mconcatIncrementalReplaceableDynMap m0 m' additionsCeased = do
119 rec vals <- holdIncremental m0 $ m' <> valChanges
120 let valChanges = fmap PatchMap $ mergeIncrementalMap $ mapIncrementalMapValues _replaceable_modify vals
121 let i = mapIncrementalMapValues _replaceable_value vals
122 noMoreAdditions <- holdDyn False $ True <$ additionsCeased
123 let replaceSelf nma x = do
126 [] -> return Nothing -- Delete self
127 [(_, n)] -> return $ Just n --TODO: What if this one is also replacing itself simultaneously?
129 result = fmap (mconcat . Map.elems) $ incrementalToDynamic $ mergeDynIncremental i
130 return $ Replaceable result $ fmapMaybe id $ updated $ zipDynWith replaceSelf noMoreAdditions $ incrementalToDynamic vals
132runDynamicWriterT :: (MonadFix m, Reflex t, MonadHold t m, Monoid w) => DynamicWriterT t w m a -> m (a, Dynamic t w)
133runDynamicWriterT (DynamicWriterT a) = do
134 (result, ws) <- runStateT a []
135 Replaceable w _ <- mconcatIncrementalReplaceableDynMap (Map.fromList $ zip [1 :: Int ..] $ reverse ws) never never
138class Monad m => MonadDynamicWriter t w m | m -> t w where
139 tellDyn :: Dynamic t w -> m ()
141instance (Monad m, Reflex t) => MonadDynamicWriter t w (DynamicWriterT t w m) where
142 tellDyn w = DynamicWriterT $ modify (Replaceable w never :)
144instance MonadReader r m => MonadReader r (DynamicWriterT t w m) where
146 local f (DynamicWriterT a) = DynamicWriterT $ mapStateT (local f) a
147 reader = lift . reader
149liftDynamicWriterTThroughSync :: Monad m' => (m (a, DynamicWriterAccumulator t w) -> m' (b, (a, DynamicWriterAccumulator t w))) -> DynamicWriterT t w m a -> DynamicWriterT t w m' (b, a)
150liftDynamicWriterTThroughSync f (DynamicWriterT child) = DynamicWriterT $ do
152 (b, (a, newS)) <- lift $ f $ runStateT child s
156instance (Deletable t m, Reflex t, Monoid w, MonadHold t m, MonadFix m) => Deletable t (DynamicWriterT t w m) where
157 deletable delete child = do
158 (result, output) <- lift $ deletable delete $ runDynamicWriterT child
159 DynamicWriterT $ modify (Replaceable output (Nothing <$ delete) :)
162instance PerformEvent t m => PerformEvent t (DynamicWriterT t w m) where
163 type Performable (DynamicWriterT t w m) = Performable m
164 performEvent_ = lift . performEvent_
165 performEvent = lift . performEvent
167instance TriggerEvent t m => TriggerEvent t (DynamicWriterT t w m) where
168 newTriggerEvent = lift newTriggerEvent
169 newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
170 newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
172instance PostBuild t m => PostBuild t (DynamicWriterT t w m) where
173 getPostBuild = lift getPostBuild
175instance MonadDynamicWriter t w m => MonadDynamicWriter t w (ReaderT r m) where
176 tellDyn = lift . tellDyn
178instance MonadState s m => MonadState s (DynamicWriterT t w m) where
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list