2{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5{-# LANGUAGE LambdaCase #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE RankNTypes #-}
8{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE TupleSections #-}
10{-# LANGUAGE TypeFamilies #-}
11{-# LANGUAGE UndecidableInstances #-}
12{-# LANGUAGE StandaloneDeriving #-}
13#ifdef USE_REFLEX_OPTIMIZER
14{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
16module Reflex.DynamicWriter.Base
22import Control.Monad.Exception
23import Control.Monad.Identity
24import Control.Monad.IO.Class
25import Control.Monad.Reader
26import Control.Monad.Ref
27import Control.Monad.State.Strict
29import Data.Dependent.Map (DMap)
30import qualified Data.Dependent.Map as DMap
31import Data.FastMutableIntMap
32import Data.Functor.Misc
33import Data.IntMap (IntMap)
34import qualified Data.IntMap as IntMap
36import qualified Data.Map as Map
38import Data.Some (Some)
41import Reflex.Adjustable.Class
43import Reflex.DynamicWriter.Class
44import Reflex.EventWriter.Class (EventWriter, tellEvent)
45import Reflex.Host.Class
46import qualified Reflex.Patch.MapWithMove as MapWithMove
47import Reflex.PerformEvent.Class
48import Reflex.PostBuild.Class
49import Reflex.Query.Class
50import Reflex.Requester.Class
51import Reflex.TriggerEvent.Class
53instance MonadTrans (DynamicWriterT t w) where
54 lift = DynamicWriterT . lift
56mapIncrementalMapValues :: (Reflex t, Patch (p v), Patch (p v'), PatchTarget (p v) ~ f v, PatchTarget (p v') ~ f v', Functor p, Functor f) => (v -> v') -> Incremental t (p v) -> Incremental t (p v')
57mapIncrementalMapValues f = unsafeMapIncremental (fmap f) (fmap f)
59mergeDynIncremental :: (Reflex t, Ord k) => Incremental t (PatchMap k (Dynamic t v)) -> Incremental t (PatchMap k v)
60mergeDynIncremental a = unsafeBuildIncremental (mapM (sample . current) =<< sample (currentIncremental a)) $ addedAndRemovedValues <> changedValues
61 where changedValues = fmap (PatchMap . fmap Just) $ mergeMapIncremental $ mapIncrementalMapValues updated a
62 addedAndRemovedValues = flip pushAlways (updatedIncremental a) $ \(PatchMap m) -> PatchMap <$> mapM (mapM (sample . current)) m
64mergeIntMapDynIncremental :: Reflex t => Incremental t (PatchIntMap (Dynamic t v)) -> Incremental t (PatchIntMap v)
65mergeIntMapDynIncremental a = unsafeBuildIncremental (mapM (sample . current) =<< sample (currentIncremental a)) $ addedAndRemovedValues <> changedValues
66 where changedValues = fmap (PatchIntMap . fmap Just) $ mergeIntMapIncremental $ mapIncrementalMapValues updated a
67 addedAndRemovedValues = flip pushAlways (updatedIncremental a) $ \(PatchIntMap m) -> PatchIntMap <$> mapM (mapM (sample . current)) m
69mergeDynIncrementalWithMove :: forall t k v. (Reflex t, Ord k) => Incremental t (PatchMapWithMove k (Dynamic t v)) -> Incremental t (PatchMapWithMove k v)
70mergeDynIncrementalWithMove a = unsafeBuildIncremental (mapM (sample . current) =<< sample (currentIncremental a)) $ alignWith f addedAndRemovedValues changedValues
71 where changedValues = mergeMapIncrementalWithMove $ mapIncrementalMapValues updated a
72 addedAndRemovedValues = flip pushAlways (updatedIncremental a) $ fmap unsafePatchMapWithMove . mapM (mapM (sample . current)) . unPatchMapWithMove
73 f :: These (PatchMapWithMove k v) (Map k v) -> PatchMapWithMove k v
74 f x = unsafePatchMapWithMove $
75 let (p, changed) = case x of
76 This p_ -> (unPatchMapWithMove p_, mempty)
78 These p_ c -> (unPatchMapWithMove p_, c)
79 (pWithNewVals, noLongerMoved) = flip runState [] $ forM p $ MapWithMove.nodeInfoMapMFrom $ \case
80 MapWithMove.From_Insert v -> return $ MapWithMove.From_Insert v
81 MapWithMove.From_Delete -> return MapWithMove.From_Delete
82 MapWithMove.From_Move k -> case Map.lookup k changed of
83 Nothing -> return $ MapWithMove.From_Move k
86 return $ MapWithMove.From_Insert v
87 noLongerMovedMap = Map.fromList $ fmap (, ()) noLongerMoved
88 in Map.differenceWith (\e _ -> Just $ MapWithMove.nodeInfoSetTo Nothing e) pWithNewVals noLongerMovedMap --TODO: Check if any in the second map are not covered?
90-- | A basic implementation of 'MonadDynamicWriter'.
91newtype DynamicWriterT t w m a = DynamicWriterT { unDynamicWriterT :: StateT [Dynamic t w] m a }
92 deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadAsyncException, MonadException) -- The list is kept in reverse order
94deriving instance MonadHold t m => MonadHold t (DynamicWriterT t w m)
95deriving instance MonadSample t m => MonadSample t (DynamicWriterT t w m)
98instance MonadRef m => MonadRef (DynamicWriterT t w m) where
99 type Ref (DynamicWriterT t w m) = Ref m
100 newRef = lift . newRef
101 readRef = lift . readRef
102 writeRef r = lift . writeRef r
104instance MonadAtomicRef m => MonadAtomicRef (DynamicWriterT t w m) where
105 atomicModifyRef r = lift . atomicModifyRef r
107instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (DynamicWriterT t w m) where
108 newEventWithTrigger = lift . newEventWithTrigger
109 newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
111-- | Run a 'DynamicWriterT' action. The dynamic writer output will be provided
112-- along with the result of the action.
113runDynamicWriterT :: (MonadFix m, Reflex t, Monoid w) => DynamicWriterT t w m a -> m (a, Dynamic t w)
114runDynamicWriterT (DynamicWriterT a) = do
115 (result, ws) <- runStateT a []
116 return (result, mconcat $ reverse ws)
118instance (Monad m, Monoid w, Reflex t) => MonadDynamicWriter t w (DynamicWriterT t w m) where
119 tellDyn w = DynamicWriterT $ modify (w :)
121instance MonadReader r m => MonadReader r (DynamicWriterT t w m) where
123 local f (DynamicWriterT a) = DynamicWriterT $ mapStateT (local f) a
124 reader = lift . reader
126instance PerformEvent t m => PerformEvent t (DynamicWriterT t w m) where
127 type Performable (DynamicWriterT t w m) = Performable m
128 performEvent_ = lift . performEvent_
129 performEvent = lift . performEvent
131instance TriggerEvent t m => TriggerEvent t (DynamicWriterT t w m) where
132 newTriggerEvent = lift newTriggerEvent
133 newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
134 newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
136instance PostBuild t m => PostBuild t (DynamicWriterT t w m) where
137 getPostBuild = lift getPostBuild
139instance MonadState s m => MonadState s (DynamicWriterT t w m) where
143newtype DynamicWriterTLoweredResult t w v a = DynamicWriterTLoweredResult (v a, Dynamic t w)
145-- | When the execution of a 'DynamicWriterT' action is adjusted using
146-- 'Adjustable', the 'Dynamic' output of that action will also be updated to
148instance (Adjustable t m, MonadFix m, Monoid w, MonadHold t m, Reflex t) => Adjustable t (DynamicWriterT t w m) where
149 runWithReplace a0 a' = do
150 (result0, result') <- lift $ runWithReplace (runDynamicWriterT a0) $ runDynamicWriterT <$> a'
151 tellDyn . join =<< holdDyn (snd result0) (snd <$> result')
152 return (fst result0, fst <$> result')
153 traverseIntMapWithKeyWithAdjust = traverseIntMapWithKeyWithAdjustImpl traverseIntMapWithKeyWithAdjust mergeIntMapDynIncremental
154 traverseDMapWithKeyWithAdjust = traverseDMapWithKeyWithAdjustImpl traverseDMapWithKeyWithAdjust mapPatchDMap weakenPatchDMapWith mergeDynIncremental
155 traverseDMapWithKeyWithAdjustWithMove = traverseDMapWithKeyWithAdjustImpl traverseDMapWithKeyWithAdjustWithMove mapPatchDMapWithMove weakenPatchDMapWithMoveWith mergeDynIncrementalWithMove
157traverseDMapWithKeyWithAdjustImpl :: forall t w k v' p p' v m. (PatchTarget (p' (Some k) (Dynamic t w)) ~ Map (Some k) (Dynamic t w), PatchTarget (p' (Some k) w) ~ Map (Some k) w, Patch (p' (Some k) w), Patch (p' (Some k) (Dynamic t w)), MonadFix m, Monoid w, Reflex t, MonadHold t m)
158 => ( (forall a. k a -> v a -> m (DynamicWriterTLoweredResult t w v' a))
161 -> m (DMap k (DynamicWriterTLoweredResult t w v'), Event t (p k (DynamicWriterTLoweredResult t w v')))
163 -> ((forall a. DynamicWriterTLoweredResult t w v' a -> v' a) -> p k (DynamicWriterTLoweredResult t w v') -> p k v')
164 -> ((forall a. DynamicWriterTLoweredResult t w v' a -> Dynamic t w) -> p k (DynamicWriterTLoweredResult t w v') -> p' (Some k) (Dynamic t w))
165 -> (Incremental t (p' (Some k) (Dynamic t w)) -> Incremental t (p' (Some k) w))
166 -> (forall a. k a -> v a -> DynamicWriterT t w m (v' a))
169 -> DynamicWriterT t w m (DMap k v', Event t (p k v'))
170traverseDMapWithKeyWithAdjustImpl base mapPatch weakenPatchWith mergeMyDynIncremental f (dm0 :: DMap k v) dm' = do
171 (result0, result') <- lift $ base (\k v -> fmap DynamicWriterTLoweredResult $ runDynamicWriterT $ f k v) dm0 dm'
172 let getValue (DynamicWriterTLoweredResult (v, _)) = v
173 getWritten (DynamicWriterTLoweredResult (_, w)) = w
174 liftedResult0 = DMap.map getValue result0
175 liftedResult' = ffor result' $ mapPatch getValue
176 liftedWritten0 :: Map (Some k) (Dynamic t w)
177 liftedWritten0 = weakenDMapWith getWritten result0
178 liftedWritten' = ffor result' $ weakenPatchWith getWritten
179 --TODO: We should be able to improve the performance here by incrementally updating the mconcat of the merged Dynamics
180 i <- holdIncremental liftedWritten0 liftedWritten'
181 tellDyn $ fmap (mconcat . Map.elems) $ incrementalToDynamic $ mergeMyDynIncremental i
182 return (liftedResult0, liftedResult')
184traverseIntMapWithKeyWithAdjustImpl :: forall t w v' p p' v m. (PatchTarget (p' (Dynamic t w)) ~ IntMap (Dynamic t w), PatchTarget (p' w) ~ IntMap w, Patch (p' w), Patch (p' (Dynamic t w)), MonadFix m, Monoid w, Reflex t, MonadHold t m, Functor p, p ~ p')
185 => ( (IntMap.Key -> v -> m (v', Dynamic t w))
188 -> m (IntMap (v', Dynamic t w), Event t (p (v', Dynamic t w)))
190 -> (Incremental t (p' (Dynamic t w)) -> Incremental t (p' w))
191 -> (IntMap.Key -> v -> DynamicWriterT t w m v')
194 -> DynamicWriterT t w m (IntMap v', Event t (p v'))
195traverseIntMapWithKeyWithAdjustImpl base mergeMyDynIncremental f (dm0 :: IntMap v) dm' = do
196 (result0, result') <- lift $ base (\k v -> runDynamicWriterT $ f k v) dm0 dm'
197 let liftedResult0 = fmap fst result0
198 liftedResult' = fmap (fmap fst) result'
199 liftedWritten0 :: IntMap (Dynamic t w)
200 liftedWritten0 = fmap snd result0
201 liftedWritten' = fmap (fmap snd) result'
202 --TODO: We should be able to improve the performance here by incrementally updating the mconcat of the merged Dynamics
203 i <- holdIncremental liftedWritten0 liftedWritten'
204 tellDyn $ fmap (mconcat . IntMap.elems) $ incrementalToDynamic $ mergeMyDynIncremental i
205 return (liftedResult0, liftedResult')
207-- | Map a function over the output of a 'DynamicWriterT'.
208withDynamicWriterT :: (Monoid w, Monoid w', Reflex t, MonadHold t m, MonadFix m)
210 -> DynamicWriterT t w m a
211 -> DynamicWriterT t w' m a
212withDynamicWriterT f dw = do
214 (r, d) <- runDynamicWriterT dw
220instance Requester t m => Requester t (DynamicWriterT t w m) where
221 type Request (DynamicWriterT t w m) = Request m
222 type Response (DynamicWriterT t w m) = Response m
223 requesting = lift . requesting
224 requesting_ = lift . requesting_
226instance (MonadQuery t q m, Monad m) => MonadQuery t q (DynamicWriterT t w m) where
227 tellQueryIncremental = lift . tellQueryIncremental
228 askQueryResult = lift askQueryResult
229 queryIncremental = lift . queryIncremental
231instance EventWriter t w m => EventWriter t w (DynamicWriterT t v m) where
232 tellEvent = lift . tellEvent
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