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 #-}
12#ifdef USE_REFLEX_OPTIMIZER
13{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
15module Reflex.DynamicWriter where
17import Control.Monad.Exception
18import Control.Monad.Identity
19import Control.Monad.IO.Class
20import Control.Monad.Reader
21import Control.Monad.Ref
22import Control.Monad.State.Strict
23import Data.Dependent.Map (DMap, DSum (..))
24import qualified Data.Dependent.Map as DMap
25import Data.Functor.Misc
27import qualified Data.Map as Map
29import Data.Some (Some)
30import qualified Data.Some as Some
33import Reflex.Host.Class
34import Reflex.PerformEvent.Class
35import Reflex.PostBuild.Class
37instance MonadTrans (DynamicWriterT t w) where
38 lift = DynamicWriterT . lift
40mconcatIncremental :: (Reflex t, MonadHold t m, MonadFix m, Monoid v, Ord k) => Map k v -> Event t (PatchMap k v) -> m (Dynamic t v)
41mconcatIncremental m0 e = do
42 d <- foldDynMaybe apply m0 e
43 return $ fmap (mconcat . Map.elems) d
45mapIncrementalMapValuesWithKey :: (Reflex t, Ord k) => (k -> v -> v') -> Incremental t (PatchMap k v) -> Incremental t (PatchMap k v')
46mapIncrementalMapValuesWithKey f = unsafeMapIncremental (Map.mapWithKey f) $ \(PatchMap m) -> PatchMap $ Map.mapWithKey (\k mv -> fmap (f k) mv) m
48mapIncrementalMapValues :: (Reflex t, Ord k) => (v -> v') -> Incremental t (PatchMap k v) -> Incremental t (PatchMap k v')
49mapIncrementalMapValues f = mapIncrementalMapValuesWithKey $ const f
51unsafeMapIncremental :: (Reflex t, Patch p, Patch p') => (PatchTarget p -> PatchTarget p') -> (p -> p') -> Incremental t p -> Incremental t p'
52unsafeMapIncremental f g a = unsafeBuildIncremental (fmap f $ sample $ currentIncremental a) $ g <$> updatedIncremental a
54incrementalExtractFunctorDMap :: (Reflex t, Ord k) => Incremental t (PatchMap k (f v)) -> Incremental t (PatchDMap (Const2 k v) f)
55incrementalExtractFunctorDMap = unsafeMapIncremental mapWithFunctorToDMap $ \(PatchMap m) -> PatchDMap $ mapWithFunctorToDMap $ fmap ComposeMaybe m
57mergeIncrementalMap :: (Reflex t, Ord k) => Incremental t (PatchMap k (Event t v)) -> Event t (Map k v)
58mergeIncrementalMap = fmap dmapToMap . mergeIncremental . incrementalExtractFunctorDMap
60holdIncrementalReplaceableMap :: forall t k v m. (MonadFix m, MonadHold t m, Reflex t, Ord k) => Map k (Replaceable t v) -> Event t (PatchMap k (Replaceable t v)) -> m (Incremental t (PatchMap k v))
61holdIncrementalReplaceableMap m0 m' = do
62 rec vals <- holdIncremental m0 $ m' <> valChanges
63 let valChanges = fmap PatchMap $ mergeIncrementalMap $ mapIncrementalMapValues _replaceable_modify vals
64 return $ mapIncrementalMapValues _replaceable_value vals
66mergeDynIncremental :: (Reflex t, Ord k) => Incremental t (PatchMap k (Dynamic t v)) -> Incremental t (PatchMap k v)
67mergeDynIncremental a = unsafeBuildIncremental (mapM (sample . current) =<< sample (currentIncremental a)) $ addedAndRemovedValues <> changedValues
68 where changedValues = fmap (PatchMap . fmap Just) $ mergeIncrementalMap $ mapIncrementalMapValues updated a
69 addedAndRemovedValues = flip pushAlways (updatedIncremental a) $ \(PatchMap m) -> PatchMap <$> mapM (mapM (sample . current)) m
71data Replaceable t w = Replaceable
72 { _replaceable_value :: w
73 , _replaceable_modify :: Event t (Maybe (Replaceable t w)) -- "Please delete" is represented with an event of Nothing; all subsequent events will be ignored
76type DynamicWriterAccumulator t w = [Dynamic t w]
78newtype 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
80instance MonadRef m => MonadRef (DynamicWriterT t w m) where
81 type Ref (DynamicWriterT t w m) = Ref m
82 newRef = lift . newRef
83 readRef = lift . readRef
84 writeRef r = lift . writeRef r
86instance MonadAtomicRef m => MonadAtomicRef (DynamicWriterT t w m) where
87 atomicModifyRef r = lift . atomicModifyRef r
89instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (DynamicWriterT t w m) where
90 newEventWithTrigger = lift . newEventWithTrigger
91 newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
93runDynamicWriterTInternal :: DynamicWriterT t w m a -> m (a, DynamicWriterAccumulator t w)
94runDynamicWriterTInternal (DynamicWriterT a) = runStateT a []
96mconcatIncrementalReplaceableDynMap :: forall m t k v.
97 (MonadFix m, MonadHold t m, Reflex t, Monoid v, Ord k)
98 => Map k (Replaceable t (Dynamic t v))
99 -> Event t (PatchMap k (Replaceable t (Dynamic t v)))
101 -> m (Replaceable t (Dynamic t v))
102mconcatIncrementalReplaceableDynMap m0 m' additionsCeased = do
103 rec vals <- holdIncremental m0 $ m' <> valChanges
104 let valChanges = fmap PatchMap $ mergeIncrementalMap $ mapIncrementalMapValues _replaceable_modify vals
105 let i = mapIncrementalMapValues _replaceable_value vals
106 noMoreAdditions <- holdDyn False $ True <$ additionsCeased
107 let replaceSelf nma x = do
110 [] -> return Nothing -- Delete self
111 [(_, n)] -> return $ Just n --TODO: What if this one is also replacing itself simultaneously?
113 result = fmap (mconcat . Map.elems) $ incrementalToDynamic $ mergeDynIncremental i
114 return $ Replaceable result $ fmapMaybe id $ updated $ zipDynWith replaceSelf noMoreAdditions $ incrementalToDynamic vals
116runDynamicWriterT :: (MonadFix m, Reflex t, Monoid w) => DynamicWriterT t w m a -> m (a, Dynamic t w)
117runDynamicWriterT (DynamicWriterT a) = do
118 (result, ws) <- runStateT a []
119 return (result, mconcat $ reverse ws)
121class Monad m => MonadDynamicWriter t w m | m -> t w where
122 tellDyn :: Dynamic t w -> m ()
124instance (Monad m, Reflex t) => MonadDynamicWriter t w (DynamicWriterT t w m) where
125 tellDyn w = DynamicWriterT $ modify (w :)
127instance MonadReader r m => MonadReader r (DynamicWriterT t w m) where
129 local f (DynamicWriterT a) = DynamicWriterT $ mapStateT (local f) a
130 reader = lift . reader
132liftDynamicWriterTThroughSync :: Monad m' => (m (a, DynamicWriterAccumulator t w) -> m' (b, (a, DynamicWriterAccumulator t w))) -> DynamicWriterT t w m a -> DynamicWriterT t w m' (b, a)
133liftDynamicWriterTThroughSync f (DynamicWriterT child) = DynamicWriterT $ do
135 (b, (a, newS)) <- lift $ f $ runStateT child s
139instance PerformEvent t m => PerformEvent t (DynamicWriterT t w m) where
140 type Performable (DynamicWriterT t w m) = Performable m
141 performEvent_ = lift . performEvent_
142 performEvent = lift . performEvent
144instance TriggerEvent t m => TriggerEvent t (DynamicWriterT t w m) where
145 newTriggerEvent = lift newTriggerEvent
146 newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
147 newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
149instance PostBuild t m => PostBuild t (DynamicWriterT t w m) where
150 getPostBuild = lift getPostBuild
152instance MonadDynamicWriter t w m => MonadDynamicWriter t w (ReaderT r m) where
153 tellDyn = lift . tellDyn
155instance MonadState s m => MonadState s (DynamicWriterT t w m) where
159newtype DynamicWriterTLoweredResult t w v = DynamicWriterTLoweredResult { unDynamicWriterTLoweredResult :: (v, Dynamic t w) }
161instance (MonadAdjust t m, MonadFix m, Monoid w, MonadHold t m, Reflex t) => MonadAdjust t (DynamicWriterT t w m) where
162 runWithReplace a0 a' = do
163 (result0, result') <- lift $ runWithReplace (runDynamicWriterT a0) $ runDynamicWriterT <$> a'
164 tellDyn . join =<< holdDyn (snd result0) (snd <$> result')
165 return (fst result0, fst <$> result')
166 sequenceDMapWithAdjust (dm0 :: DMap k (DynamicWriterT t w m)) dm' = do
167 let loweredDm0 = mapKeyValuePairsMonotonic (\(k :=> v) -> WrapArg k :=> fmap DynamicWriterTLoweredResult (runDynamicWriterT v)) dm0
168 let loweredDm' = ffor dm' $ \(PatchDMap p) -> PatchDMap $
169 mapKeyValuePairsMonotonic (\(k :=> ComposeMaybe mv) -> WrapArg k :=> ComposeMaybe (fmap (fmap DynamicWriterTLoweredResult . runDynamicWriterT) mv)) p
170 (result0, result') <- lift $ sequenceDMapWithAdjust loweredDm0 loweredDm'
171 let getValue (DynamicWriterTLoweredResult (v, _)) = v
172 getWritten (DynamicWriterTLoweredResult (_, w)) = w
173 liftedResult0 = mapKeyValuePairsMonotonic (\(WrapArg k :=> Identity r) -> k :=> Identity (getValue r)) result0
174 liftedResult' = ffor result' $ \(PatchDMap p) -> PatchDMap $
175 mapKeyValuePairsMonotonic (\(WrapArg k :=> ComposeMaybe mr) -> k :=> ComposeMaybe (fmap (Identity . getValue . runIdentity) mr)) p
176 liftedWritten0 :: Map (Some k) (Dynamic t w)
177 liftedWritten0 = Map.fromDistinctAscList $ (\(WrapArg k :=> Identity r) -> (Some.This k, getWritten r)) <$> DMap.toList result0
178 liftedWritten' = ffor result' $ \(PatchDMap p) -> PatchMap $
179 Map.fromDistinctAscList $ (\(WrapArg k :=> ComposeMaybe mr) -> (Some.This k, fmap (getWritten . runIdentity) mr)) <$> DMap.toList p
180 --TODO: We should be able to improve the performance here by incrementally updating the mconcat of the merged Dynamics
181 i <- holdIncremental liftedWritten0 liftedWritten'
182 tellDyn $ fmap (mconcat . Map.elems) $ incrementalToDynamic $ mergeDynIncremental i
183 return (liftedResult0, liftedResult')
185withDynamicWriterT :: (Monoid w, Reflex t, MonadHold t m, MonadFix m)
187 -> DynamicWriterT t w m a
188 -> DynamicWriterT t w' m a
189withDynamicWriterT f dw = do
191 (r, d) <- runDynamicWriterT dw
197instance MonadRequest t m => MonadRequest t (DynamicWriterT t w m) where
198 type Request (DynamicWriterT t w m) = Request m
199 type Response (DynamicWriterT t w m) = Response m
200 withRequesting f = DynamicWriterT $ withRequesting $ unDynamicWriterT . f
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