on develop help sign in
More WIP (doesn't build)
commit44cfdfa621f34fefe8b8fa89d01ef6f5a5149467 authorRyan Trinkle <ryan.trinkle@gmail.com> dateMon 16 Sep 2019, 22:34 (7 years ago) parent531cc28
6 files changed+702−673
src/Data/TagMap.hs+4 src/Data/Unique/Tag/Local.hs+3−3 src/Data/Unique/Tag/Local/Internal.hs+24−22 src/Reflex/PerformEvent/Base.hs+9−9 src/Reflex/Requester/Base.hs+1−639 src/Reflex/Requester/Base/Internal.hs+661
src/Data/TagMap.hs+4
@@ -5,6 +5,7 @@ module Data.TagMap
55 , unTagMap
66 , fromDMap
77 , toDMap
8+ , fromList
89 , insert
910 ) where
1011
@@ -29,3 +30,6 @@ toDMap = DMap.fromDistinctAscList . fmap (\(k, v) -> (unsafeTagFromId k :=> (uns
2930
3031insert :: forall x a v. Tag x a -> v a -> TagMap x v -> TagMap x v
3132insert k v = TagMap . IntMap.insert (tagId k) ((unsafeCoerce :: v a -> Any) v) . unTagMap
33+
34+fromList :: [DSum (Tag x) v] -> TagMap x v
35+fromList = TagMap . IntMap.fromList . fmap (\(t :=> v) -> (tagId t, (unsafeCoerce :: v a -> Any) v))
src/Data/Unique/Tag/Local.hs+3−3
@@ -1,11 +1,11 @@
11module Data.Unique.Tag.Local
22 ( Tag
33 , TagGen (..)
4− , TagGenT
54 , tagId
65 , unsafeTagFromId
7− , runTagGenT
8− , mapTagGenT
6+ , newTag
7+ , newTagGen
8+ , withTagGen
99 ) where
1010
1111import Data.Unique.Tag.Local.Internal
src/Data/Unique/Tag/Local/Internal.hs+24−22
@@ -1,3 +1,7 @@
1+-- | The type-safety of this module depends on two assumptions:
2+-- 1. If the `s` parameters on two `TagGen`s can unify, then they contain the same MutVar
3+-- 2. Two Tag values made from the same TagGen never contain the same Int
4+
15{-# LANGUAGE EmptyDataDecls #-}
26{-# LANGUAGE DeriveFunctor #-}
37{-# LANGUAGE GeneralizedNewtypeDeriving #-}
@@ -11,6 +15,9 @@ import Control.Monad.Exception
1115import Control.Monad.Primitive
1216import Control.Monad.Reader
1317import Data.Primitive.MutVar
18+import Data.GADT.Compare
19+import Data.Some
20+import Unsafe.Coerce
1421
1522newtype Tag x a = Tag Int
1623
@@ -23,29 +30,24 @@ tagId (Tag n) = n
2330unsafeTagFromId :: Int -> Tag x a
2431unsafeTagFromId n = Tag n
2532
26−class TagGen m where
27− type TagScope m :: *
28− -- | Note: this will throw an exception if its internal counter would wrap around
29− mkTag :: m (Tag (TagScope m) a)
30−
31−newtype TagGenT (s :: *) m a = TagGenT { unTagGenT :: ReaderT (MutVar (PrimState m) Int) m a }
32− deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException)
33−
34−instance MonadTrans (TagGenT s) where
35− lift = TagGenT . lift
33+-- We use Int because it is supported by e.g. IntMap
34+newtype TagGen ps s = TagGen { unTagGen :: MutVar ps Int }
3635
37−data TagGenTScope (ps :: *) (s :: *)
36+instance GEq (TagGen ps) where
37+ TagGen a `geq` TagGen b =
38+ if a == b
39+ then Nothing
40+ else Just $ unsafeCoerce Refl
3841
39−instance PrimMonad m => TagGen (TagGenT s m) where
40− type TagScope (TagGenT s m) = s
41− mkTag = TagGenT $ ReaderT $ \r -> do
42− n <- atomicModifyMutVar' r $ \x -> (succ x, x)
43− pure $ Tag n
42+newTag :: PrimMonad m => TagGen (PrimState m) s -> m (Tag s a)
43+newTag (TagGen r) = do
44+ n <- atomicModifyMutVar' r $ \x -> (succ x, x)
45+ pure $ Tag n
4446
45−runTagGenT :: forall m a. PrimMonad m => (forall s. TagGenT s m a) -> m a
46−runTagGenT (TagGenT a :: TagGenT (TagGenTScope (PrimState m) ()) m a) = do
47− r <- newMutVar minBound
48− runReaderT a r
47+newTagGen :: PrimMonad m => m (Some (TagGen (PrimState m)))
48+newTagGen = Some . TagGen <$> newMutVar minBound
4949
50−mapTagGenT :: PrimState m ~ PrimState n => (m a -> n b) -> TagGenT s m a -> TagGenT s n b
51−mapTagGenT f (TagGenT a) = TagGenT $ mapReaderT f a
50+withTagGen :: PrimMonad m => (forall s. TagGen (PrimState m) s -> m a) -> m a
51+withTagGen f = do
52+ g <- newTagGen
53+ withSome g f
src/Reflex/PerformEvent/Base.hs+9−9
@@ -28,7 +28,7 @@ import Reflex.Class
2828import Reflex.Adjustable.Class
2929import Reflex.Host.Class
3030import Reflex.PerformEvent.Class
31−import Reflex.Requester.Base
31+import Reflex.Requester.Base.Internal
3232import Reflex.Requester.Class
3333
3434import Control.Lens
@@ -82,23 +82,23 @@ newtype NullAdjustable t m a = NullAdjustable { unNullAdjustable :: m a }
8282instance PrimMonad m => PrimMonad (NullAdjustable t m) where
8383 type PrimState (NullAdjustable t m) = PrimState m
8484
85−instance Adjustable t (PerformEvent t m) where
86− runWithReplace a0 a' = PerformEventT $ do
87− runWithReplace (unPerformEventT a0) a'
85+instance (ReflexHost t, PrimMonad (HostFrame t)) => Adjustable t (PerformEventT t m) where
86+ runWithReplace (PerformEventT (RequesterT a0)) a' = PerformEventT $ RequesterT $ do
87+ (s, tg) <- RequesterInternalT ask
88+ newA <- requestingIdentity $ undefined <$> a'
89+ runWithReplace a0 never
8890
89−{-
9091instance Adjustable t (NullAdjustable t m) where
9192 runWithReplace a0 a' = NullAdjustable $ do
92− result0 <- lift a0
93− result' <- requestingIdentity a'
9493 return (result0, result')
9594 traverseDMapWithKeyWithAdjust = defaultAdjustBase traversePatchDMapWithKey
9695 traverseDMapWithKeyWithAdjustWithMove = defaultAdjustBase traversePatchDMapWithMoveWithKey
97−-}
96+
9897{-
9998 traverseIntMapWithKeyWithAdjust = defaultAdjustIntBase traverseIntMapPatchWithKey
10099-}
101100
101+{-
102102instance (ReflexHost t, PrimMonad (HostFrame t)) => Adjustable t (PerformEventT t m) where
103103 runWithReplace outerA0 outerA' = PerformEventT $ runWithReplaceRequesterTWith f (coerce outerA0) (coerceEvent outerA')
104104 where f :: HostFrame t a -> Event t (HostFrame t b) -> RequesterT t (HostFrame t) Identity (HostFrame t) (a, Event t b)
@@ -106,7 +106,6 @@ instance (ReflexHost t, PrimMonad (HostFrame t)) => Adjustable t (PerformEventT
106106 result0 <- lift a0
107107 result' <- requestingIdentity a'
108108 return (result0, result')
109− {-
110109 traverseIntMapWithKeyWithAdjust f outerDm0 outerDm' = PerformEventT $ traverseIntMapWithKeyWithAdjustRequesterTWith (defaultAdjustIntBase traverseIntMapPatchWithKey) patchIntMapNewElementsMap mergeIntIncremental (\k v -> unPerformEventT $ f k v) (coerce outerDm0) (coerceEvent outerDm')
111110 traverseDMapWithKeyWithAdjust f outerDm0 outerDm' = PerformEventT $ traverseDMapWithKeyWithAdjustRequesterTWith (defaultAdjustBase traversePatchDMapWithKey) mapPatchDMap weakenPatchDMapWith patchMapNewElementsMap mergeMapIncremental (\k v -> unPerformEventT $ f k v) (coerce outerDm0) (coerceEvent outerDm')
112111 traverseDMapWithKeyWithAdjustWithMove f outerDm0 outerDm' = PerformEventT $ traverseDMapWithKeyWithAdjustRequesterTWith (defaultAdjustBase traversePatchDMapWithMoveWithKey) mapPatchDMapWithMove weakenPatchDMapWithMoveWith patchMapWithMoveNewElementsMap mergeMapIncrementalWithMove (\k v -> unPerformEventT $ f k v) (coerce outerDm0) (coerceEvent outerDm')
@@ -150,6 +149,7 @@ hostPerformEventT :: forall t m a.
150149 , MonadReflexHost t m
151150 , MonadRef m
152151 , Ref m ~ Ref IO
152+ , PrimMonad (HostFrame t)
153153 )
154154 => PerformEventT t m a
155155 -> m (a, FireCommand t m)
src/Reflex/Requester/Base.hs+1−639
@@ -1,24 +1,5 @@
11-- | This module provides 'RequesterT', the standard implementation of
22-- 'Requester'.
3−{-# LANGUAGE AllowAmbiguousTypes #-}
4−{-# LANGUAGE CPP #-}
5−{-# LANGUAGE EmptyDataDecls #-}
6−{-# LANGUAGE ExistentialQuantification #-}
7−{-# LANGUAGE FlexibleInstances #-}
8−{-# LANGUAGE GADTs #-}
9−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
10−{-# LANGUAGE MultiParamTypeClasses #-}
11−{-# LANGUAGE Rank2Types #-}
12−{-# LANGUAGE RecursiveDo #-}
13−{-# LANGUAGE ScopedTypeVariables #-}
14−{-# LANGUAGE StandaloneDeriving #-}
15−{-# LANGUAGE TypeFamilies #-}
16−{-# LANGUAGE TypeOperators #-}
17−{-# LANGUAGE UndecidableInstances #-}
18−{-# LANGUAGE InstanceSigs #-}
19−#ifdef USE_REFLEX_OPTIMIZER
20−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
21−#endif
223module Reflex.Requester.Base
234 ( RequesterT (..)
245 , runRequesterT
@@ -35,623 +16,4 @@ module Reflex.Requester.Base
3516-- , requesting'
3617 ) where
3718
38−import Reflex.Class
39−import Reflex.Adjustable.Class
40−import Reflex.Dynamic
41−import Reflex.Host.Class
42−import Reflex.PerformEvent.Class
43−import Reflex.PostBuild.Class
44−import Reflex.Requester.Class
45−import Reflex.TriggerEvent.Class
46−import Reflex.EventWriter.Base
47−import Reflex.EventWriter.Class
48−
49−import Control.Applicative (liftA2)
50−import Control.Monad.Exception
51−import Control.Monad.Identity
52−import Control.Monad.Primitive
53−import Control.Monad.Reader
54−import Control.Monad.Ref
55−import Control.Monad.State.Strict
56−import Data.Bits
57−import Data.Coerce
58−import Data.Dependent.Map (DMap, DSum (..))
59−import qualified Data.Dependent.Map as DMap
60−import Data.Functor.Compose
61−import Data.Functor.Misc
62−import Data.IntMap.Strict (IntMap)
63−import qualified Data.IntMap.Strict as IntMap
64−import Data.Map (Map)
65−import qualified Data.Map as Map
66−import Data.Monoid ((<>))
67−import Data.Proxy
68−import qualified Data.Semigroup as S
69−import Data.Some (Some(Some))
70−import Data.Type.Equality
71−import Data.Sequence (Seq)
72−import qualified Data.Sequence as Seq
73−import Data.TagMap
74−import Reflex.FanTag
75−import Data.Unique.Tag.Local
76−import qualified Data.Unique.Tag as Global
77−import Data.GADT.Compare
78−
79−data RequestData m request = forall s. RequestData !(Global.Tag (PrimState m) s) !(Seq (RequestEnvelope s request))
80−data ResponseData m response = forall s. ResponseData !(Global.Tag (PrimState m) s) !(TagMap s response)
81−
82−runRequesterT :: forall t request response m a
83− . ( Reflex t
84− , PrimMonad m
85− , MonadFix m
86− )
87− => RequesterT t request response m a
88− -> Event t (ResponseData m response)
89− -> m (a, Event t (RequestData m request))
90−runRequesterT (RequesterT a) wrappedResponses = withRequesterInternalT $ \(requests :: Event t (Seq (RequestEnvelope s request))) -> do
91− t :: Global.Tag (PrimState m) s <- lift Global.newTag
92− result <- a
93− let responses = fforMaybe wrappedResponses $ \(ResponseData s m) -> case s `geq` t of
94− Nothing -> Nothing --TODO: Warn somehow
95− Just Refl -> Just m
96− pure (responses, (result, fmap (RequestData t) requests))
97−
98−instance MonadTrans (RequesterInternalT s t request response) where
99− lift = RequesterInternalT . lift . lift . lift
100−
101−instance MonadTrans (RequesterT t request response) where
102− lift a = RequesterT $ RequesterInternalT $ lift $ lift $ lift a
103−
104−-- | Run a 'RequesterT' action. The resulting 'Event' will fire whenever
105−-- requests are made, and responses should be provided in the input 'Event'.
106−-- The 'Tag' keys will be used to return the responses to the same place the
107−-- requests were issued.
108−withRequesterInternalT :: (Reflex t, PrimMonad m, MonadFix m)
109− => (forall s. Event t (Seq (RequestEnvelope s request)) -> RequesterInternalT s t request response m (Event t (TagMap s response), a))
110− -> m a
111−withRequesterInternalT f = runTagGenT $ do
112− rec let RequesterInternalT a = f requests
113− ((responses, result), requests) <- runEventWriterT $ runReaderT a (fanTag responses)
114− pure result
115−
116−data RequestEnvelope s request = forall a. RequestEnvelope {-# UNPACK #-} !(Maybe (Tag s a)) !(request a)
117−
118−newtype RequesterT t (request :: * -> *) (response :: * -> *) m a = RequesterT { unRequesterT :: forall s. RequesterInternalT s t request response m a }
119−
120−instance Functor m => Functor (RequesterT t request response m) where
121− fmap f (RequesterT x) = RequesterT $ fmap f x
122−
123−instance Monad m => Applicative (RequesterT t request response m) where
124− pure x = RequesterT $ pure x
125− RequesterT f <*> RequesterT x = RequesterT $ f <*> x
126− liftA2 f (RequesterT a) (RequesterT b) = RequesterT $ liftA2 f a b
127− RequesterT f <* RequesterT x = RequesterT $ f <* x
128− RequesterT f *> RequesterT x = RequesterT $ f *> x
129−
130−instance Monad m => Monad (RequesterT t request response m) where
131− return = pure
132− RequesterT mx >>= f = RequesterT $ mx >>= \x -> case f x of
133− RequesterT y -> y
134−
135−instance MonadFix m => MonadFix (RequesterT t request response m) where
136− mfix f = RequesterT $ mfix $ \x -> case f x of
137− RequesterT a -> a
138−
139−instance MonadIO m => MonadIO (RequesterT t request respnose m) where
140− liftIO a = RequesterT $ liftIO a
141−
142−instance MonadException m => MonadException (RequesterT t request respnose m) where
143− throw e = RequesterT $ throw e
144−
145−newtype RequesterInternalT s t request response m a = RequesterInternalT { unRequesterInternalT :: ReaderT (EventSelectorTag t s response) (EventWriterT t (Seq (RequestEnvelope s request)) (TagGenT s m)) a }
146− deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException)
147−
148−instance MonadSample t m => MonadSample t (RequesterT t request response m)
149−instance MonadHold t m => MonadHold t (RequesterT t request response m)
150−instance PostBuild t m => PostBuild t (RequesterT t request response m)
151−instance TriggerEvent t m => TriggerEvent t (RequesterT t request response m)
152−
153−instance PrimMonad m => PrimMonad (RequesterT t request response m) where
154− type PrimState (RequesterT t request response m) = PrimState m
155− primitive = lift . primitive
156−
157−-- TODO: Monoid and Semigroup can likely be derived once StateT has them.
158−instance (Monoid a, Monad m) => Monoid (RequesterT t request response m a) where
159− mempty = pure mempty
160− mappend = liftA2 mappend
161−
162−instance (S.Semigroup a, Monad m) => S.Semigroup (RequesterT t request response m a) where
163− (<>) = liftA2 (S.<>)
164−
165−instance PerformEvent t m => PerformEvent t (RequesterT t request response m) where
166− type Performable (RequesterT t request response m) = Performable m
167− performEvent_ = lift . performEvent_
168− performEvent = lift . performEvent
169−
170−instance MonadRef m => MonadRef (RequesterT t request response m) where
171− type Ref (RequesterT t request response m) = Ref m
172− newRef = lift . newRef
173− readRef = lift . readRef
174− writeRef r = lift . writeRef r
175−
176−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (RequesterT t request response m) where
177− newEventWithTrigger = lift . newEventWithTrigger
178− newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
179−
180−instance MonadReader r m => MonadReader r (RequesterT t request response m) where
181− ask = lift ask
182− local f (RequesterT a) = RequesterT $ RequesterInternalT $ mapReaderT (mapEventWriterT $ mapTagGenT $ local f) $ unRequesterInternalT a
183− reader = lift . reader
184−
185−instance (Reflex t, PrimMonad m) => Requester t (RequesterT t request response m) where
186− type Request (RequesterT t request response m) = request
187− type Response (RequesterT t request response m) = response
188− requesting e = RequesterT $ RequesterInternalT $ do
189− t <- lift $ lift mkTag
190− tellEvent $ fmapCheap (Seq.singleton . RequestEnvelope (Just t)) e
191− s <- ask
192− pure $ selectTag s t
193− requesting_ e = RequesterT $ RequesterInternalT $ do
194− tellEvent $ fmapCheap (Seq.singleton . RequestEnvelope Nothing) e
195−
196−
197−{-# INLINABLE runWithReplaceRequesterTWith #-}
198−runWithReplaceRequesterTWith :: forall m t request response a b. (Reflex t, MonadHold t m
199− , MonadFix m
200− )
201− => (forall a' b'. m a' -> Event t (m b') -> RequesterT t request response m (a', Event t b'))
202− -> RequesterT t request response m a
203− -> Event t (RequesterT t request response m b)
204− -> RequesterT t request response m (a, Event t b)
205−runWithReplaceRequesterTWith f (RequesterT a0) a' = RequesterT $ do
206− pure undefined
207−
208−{-
209−import GHC.Exts (Any)
210−import Unsafe.Coerce
211−
212−--TODO: Make this module type-safe
213−
214−newtype TagMap (f :: * -> *) = TagMap (IntMap Any)
215−
216−newtype RequesterData f = RequesterData (TagMap (Entry f))
217−
218−data RequesterDataKey a where
219− RequesterDataKey_Single :: {-# UNPACK #-} !(MyTag (Single a)) -> RequesterDataKey a
220− RequesterDataKey_Multi :: {-# UNPACK #-} !(MyTag Multi) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a --TODO: Don't put a second Int here (or in the other Multis); use a single Int instead
221− RequesterDataKey_Multi2 :: {-# UNPACK #-} !(MyTag (Multi2 k)) -> !(Some k) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
222− RequesterDataKey_Multi3 :: {-# UNPACK #-} !(MyTag Multi3) -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
223−
224−singletonRequesterData :: RequesterDataKey a -> f a -> RequesterData f
225−singletonRequesterData rdk v = case rdk of
226− RequesterDataKey_Single k -> RequesterData $ singletonTagMap k $ Entry v
227− RequesterDataKey_Multi k k' k'' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ singletonRequesterData k'' v
228− RequesterDataKey_Multi2 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ Map.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
229− RequesterDataKey_Multi3 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
230−
231−requesterDataToList :: RequesterData f -> [DSum RequesterDataKey f]
232−requesterDataToList (RequesterData m) = do
233− k :=> Entry e <- tagMapToList m
234− case myKeyType k of
235− MyTagType_Single -> return $ RequesterDataKey_Single k :=> e
236− MyTagType_Multi -> do
237− (k', e') <- IntMap.toList e
238− k'' :=> e'' <- requesterDataToList e'
239− return $ RequesterDataKey_Multi k k' k'' :=> e''
240− MyTagType_Multi2 -> do
241− (k', e') <- Map.toList e
242− (k'', e'') <- IntMap.toList e'
243− k''' :=> e''' <- requesterDataToList e''
244− return $ RequesterDataKey_Multi2 k k' k'' k''' :=> e'''
245− MyTagType_Multi3 -> do
246− (k', e') <- IntMap.toList e
247− (k'', e'') <- IntMap.toList e'
248− k''' :=> e''' <- requesterDataToList e''
249− return $ RequesterDataKey_Multi3 k k' k'' k''' :=> e'''
250−
251−singletonTagMap :: forall f a. MyTag a -> f a -> TagMap f
252−singletonTagMap (MyTag k) v = TagMap $ IntMap.singleton k $ (unsafeCoerce :: f a -> Any) v
253−
254−tagMapToList :: forall f. TagMap f -> [DSum MyTag f]
255−tagMapToList (TagMap m) = f <$> IntMap.toList m
256− where f :: (Int, Any) -> DSum MyTag f
257− f (k, v) = MyTag k :=> (unsafeCoerce :: Any -> f a) v
258−
259−traverseTagMapWithKey :: forall t f g. Applicative t => (forall a. MyTag a -> f a -> t (g a)) -> TagMap f -> t (TagMap g)
260−traverseTagMapWithKey f (TagMap m) = TagMap <$> IntMap.traverseWithKey g m
261− where
262− g :: Int -> Any -> t Any
263− g k v = (unsafeCoerce :: g a -> Any) <$> f (MyTag k) ((unsafeCoerce :: Any -> f a) v)
264−
265−-- | Runs in reverse to accommodate for the fact that we accumulate it in reverse
266−traverseRequesterData :: forall m request response. Applicative m => (forall a. request a -> m (response a)) -> RequesterData request -> m (RequesterData response)
267−traverseRequesterData f (RequesterData m) = RequesterData <$> traverseTagMapWithKey go m --TODO: reverse this, since our tags are in reverse order
268− where go :: forall x. MyTag x -> Entry request x -> m (Entry response x)
269− go k (Entry request) = Entry <$> case myKeyType k of
270− MyTagType_Single -> f request
271− MyTagType_Multi -> traverse (traverseRequesterData f) request
272− MyTagType_Multi2 -> traverse (traverse (traverseRequesterData f)) request
273− MyTagType_Multi3 -> traverse (traverse (traverseRequesterData f)) request
274−
275−-- | 'traverseRequesterData' with its arguments flipped
276−forRequesterData :: forall request response m. Applicative m => RequesterData request -> (forall a. request a -> m (response a)) -> m (RequesterData response)
277−forRequesterData r f = traverseRequesterData f r
278−
279−data MyTagType :: * -> * where
280− MyTagType_Single :: MyTagType (Single a)
281− MyTagType_Multi :: MyTagType Multi
282− MyTagType_Multi2 :: MyTagType (Multi2 k)
283− MyTagType_Multi3 :: MyTagType Multi3
284−
285−myKeyType :: MyTag x -> MyTagType x
286−myKeyType (MyTag k) = case k .&. 0x3 of
287− 0x0 -> unsafeCoerce MyTagType_Single
288− 0x1 -> unsafeCoerce MyTagType_Multi
289− 0x2 -> unsafeCoerce MyTagType_Multi2
290− 0x3 -> unsafeCoerce MyTagType_Multi3
291− t -> error $ "Reflex.Requester.Base.myKeyType: no such key type" <> show t
292−
293−data Single a
294−data Multi
295−data Multi2 (k :: * -> *)
296−data Multi3
297−
298−class MyTagTypeOffset x where
299− myTagTypeOffset :: proxy x -> Int
300−
301−instance MyTagTypeOffset (Single a) where
302− myTagTypeOffset _ = 0x0
303−
304−instance MyTagTypeOffset Multi where
305− myTagTypeOffset _ = 0x1
306−
307−instance MyTagTypeOffset (Multi2 k) where
308− myTagTypeOffset _ = 0x2
309−
310−instance MyTagTypeOffset Multi3 where
311− myTagTypeOffset _ = 0x3
312−
313−type family EntryContents request a where
314− EntryContents request (Single a) = request a
315− EntryContents request Multi = IntMap (RequesterData request)
316− EntryContents request (Multi2 k) = Map (Some k) (IntMap (RequesterData request))
317− EntryContents request Multi3 = IntMap (IntMap (RequesterData request))
318−
319−newtype Entry request x = Entry { unEntry :: EntryContents request x }
320−
321−{-# INLINE singleEntry #-}
322−singleEntry :: f a -> Entry f (Single a)
323−singleEntry = Entry
324−
325−{-# INLINE multiEntry #-}
326−multiEntry :: IntMap (RequesterData f) -> Entry f Multi
327−multiEntry = Entry
328−
329−{-# INLINE unMultiEntry #-}
330−unMultiEntry :: Entry f Multi -> IntMap (RequesterData f)
331−unMultiEntry = unEntry
332−
333−-- | We use a hack here to pretend we have x ~ request a; we don't want to use a GADT, because GADTs (even with zero-size existential contexts) can't be newtypes
334−-- WARNING: This type should never be exposed. In particular, this is extremely unsound if a MyTag from one run of runRequesterT is ever compared against a MyTag from another
335−newtype MyTag x = MyTag Int deriving (Show, Eq, Ord, Enum)
336−
337−newtype MyTagWrap (f :: * -> *) x = MyTagWrap Int deriving (Show, Eq, Ord, Enum)
338−
339−{-# INLINE castMyTagWrap #-}
340−castMyTagWrap :: MyTagWrap f (Entry f x) -> MyTagWrap g (Entry g x)
341−castMyTagWrap = coerce
342−
343−instance GEq MyTag where
344− (MyTag a) `geq` (MyTag b) =
345− if a == b
346− then Just $ unsafeCoerce Refl
347− else Nothing
348−
349−instance GCompare MyTag where
350− (MyTag a) `gcompare` (MyTag b) =
351− case a `compare` b of
352− LT -> GLT
353− EQ -> unsafeCoerce GEQ
354− GT -> GGT
355−
356−instance GEq (MyTagWrap f) where
357− (MyTagWrap a) `geq` (MyTagWrap b) =
358− if a == b
359− then Just $ unsafeCoerce Refl
360− else Nothing
361−
362−instance GCompare (MyTagWrap f) where
363− (MyTagWrap a) `gcompare` (MyTagWrap b) =
364− case a `compare` b of
365− LT -> GLT
366− EQ -> unsafeCoerce GEQ
367− GT -> GGT
368−
369−data RequesterState t (request :: * -> *) = RequesterState
370− { _requesterState_nextMyTag :: {-# UNPACK #-} !Int -- Starts at -4 and goes down by 4 each time, to accommodate two 'type' bits at the bottom
371− , _requesterState_requests :: ![(Int, Event t Any)]
372− }
373−
374−-- | A basic implementation of 'Requester'.
375−newtype RequesterT t request (response :: * -> *) m a = RequesterT { unRequesterT :: StateT (RequesterState t request) (ReaderT (EventSelectorInt t Any) m) a }
376− deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException
377−-- MonadAsyncException can't be derived on ghc-8.0.1; we use base-4.9.1 as a proxy for ghc-8.0.2
378−#if MIN_VERSION_base(4,9,1)
379− , MonadAsyncException
380−#endif
381− )
382−
383−
384−-- | Run a 'RequesterT' action. The resulting 'Event' will fire whenever
385−-- requests are made, and responses should be provided in the input 'Event'.
386−-- The 'Tag' keys will be used to return the responses to the same place the
387−-- requests were issued.
388−runRequesterT :: (Reflex t, Monad m)
389− => RequesterT t request response m a
390− -> Event t (RequesterData response) --TODO: This DMap will be in reverse order, so we need to make sure the caller traverses it in reverse
391− -> m (a, Event t (RequesterData request)) --TODO: we need to hide these 'MyTag's here, because they're unsafe to mix in the wild
392−runRequesterT (RequesterT a) responses = do
393− (result, s) <- runReaderT (runStateT a $ RequesterState (-4) []) $ fanInt $
394− coerceEvent responses
395− return (result, fmapCheap (RequesterData . TagMap) $ mergeInt $ IntMap.fromDistinctAscList $ _requesterState_requests s)
396−
397−-- | Map a function over the request and response of a 'RequesterT'
398−withRequesterT
399− :: (Reflex t, MonadFix m)
400− => (forall x. req x -> req' x) -- ^ The function to map over the request
401− -> (forall x. rsp' x -> rsp x) -- ^ The function to map over the response
402− -> RequesterT t req rsp m a -- ^ The internal 'RequesterT' whose input and output will be transformed
403− -> RequesterT t req' rsp' m a -- ^ The resulting 'RequesterT'
404−withRequesterT freq frsp child = do
405− rec let rsp = fmap (runIdentity . traverseRequesterData (Identity . frsp)) rsp'
406− (a, req) <- lift $ runRequesterT child rsp
407− rsp' <- fmap (flip selectInt 0 . fanInt . fmapCheap unMultiEntry) $ requesting' $
408− fmapCheap (multiEntry . IntMap.singleton 0) $ fmap (runIdentity . traverseRequesterData (Identity . freq)) req
409− return a
410−
411−instance (Reflex t, Monad m) => Requester t (RequesterT t request response m) where
412− type Request (RequesterT t request response m) = request
413− type Response (RequesterT t request response m) = response
414− requesting = fmap coerceEvent . responseFromTag . castMyTagWrap <=< tagRequest . (coerceEvent :: Event t (request a) -> Event t (Entry request (Single a)))
415− requesting_ = void . tagRequest . fmapCheap singleEntry
416−
417−{-# INLINE tagRequest #-}
418−tagRequest :: forall m x t request response. (Monad m, MyTagTypeOffset x) => Event t (Entry request x) -> RequesterT t request response m (MyTagWrap request (Entry request x))
419−tagRequest req = do
420− old <- RequesterT get
421− let n = _requesterState_nextMyTag old .|. myTagTypeOffset (Proxy :: Proxy x)
422− t = MyTagWrap n
423− RequesterT $ put $ RequesterState
424− { _requesterState_nextMyTag = _requesterState_nextMyTag old - 0x4
425− , _requesterState_requests = (n, (unsafeCoerce :: Event t (Entry request x) -> Event t Any) req) : _requesterState_requests old
426− }
427− return t
428−
429−{-# INLINE responseFromTag #-}
430−responseFromTag :: Monad m => MyTagWrap response (Entry response x) -> RequesterT t request response m (Event t (Entry response x))
431−responseFromTag (MyTagWrap t) = do
432− responses :: EventSelectorInt t Any <- RequesterT ask
433− return $ (unsafeCoerce :: Event t Any -> Event t (Entry response x)) $ selectInt responses t
434−
435−instance MonadTrans (RequesterT t request response) where
436− lift = RequesterT . lift . lift
437−
438−instance PerformEvent t m => PerformEvent t (RequesterT t request response m) where
439− type Performable (RequesterT t request response m) = Performable m
440− performEvent_ = lift . performEvent_
441− performEvent = lift . performEvent
442−
443−instance MonadRef m => MonadRef (RequesterT t request response m) where
444− type Ref (RequesterT t request response m) = Ref m
445− newRef = lift . newRef
446− readRef = lift . readRef
447− writeRef r = lift . writeRef r
448−
449−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (RequesterT t request response m) where
450− newEventWithTrigger = lift . newEventWithTrigger
451− newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
452−
453−instance MonadReader r m => MonadReader r (RequesterT t request response m) where
454− ask = lift ask
455− local f (RequesterT a) = RequesterT $ mapStateT (mapReaderT $ local f) a
456− reader = lift . reader
457−
458−instance (Reflex t, Adjustable t m, MonadHold t m, MonadFix m) => Adjustable t (RequesterT t request response m) where
459− runWithReplace = runWithReplaceRequesterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm'
460− traverseIntMapWithKeyWithAdjust = traverseIntMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseIntMapWithKeyWithAdjust f dm0 dm') patchIntMapNewElementsMap mergeIntIncremental
461− {-# INLINABLE traverseDMapWithKeyWithAdjust #-}
462− traverseDMapWithKeyWithAdjust = traverseDMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjust f dm0 dm') mapPatchDMap weakenPatchDMapWith patchMapNewElementsMap mergeMapIncremental
463− traverseDMapWithKeyWithAdjustWithMove = traverseDMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjustWithMove f dm0 dm') mapPatchDMapWithMove weakenPatchDMapWithMoveWith patchMapWithMoveNewElementsMap mergeMapIncrementalWithMove
464−
465−requesting' :: (MyTagTypeOffset x, Monad m) => Event t (Entry request x) -> RequesterT t request response m (Event t (Entry response x))
466−requesting' = responseFromTag . castMyTagWrap <=< tagRequest
467−
468−{-# INLINABLE runWithReplaceRequesterTWith #-}
469−runWithReplaceRequesterTWith :: forall m t request response a b. (Reflex t, MonadHold t m
470− , MonadFix m
471− )
472− => (forall a' b'. m a' -> Event t (m b') -> RequesterT t request response m (a', Event t b'))
473− -> RequesterT t request response m a
474− -> Event t (RequesterT t request response m b)
475− -> RequesterT t request response m (a, Event t b)
476−runWithReplaceRequesterTWith f a0 a' = do
477− rec na' <- numberOccurrencesFrom 1 a'
478− responses <- fmap (fmapCheap unMultiEntry) $ requesting' $ fmapCheap multiEntry $ switchPromptlyDyn requests --TODO: Investigate whether we can really get rid of the prompt stuff here
479− let responses' = fanInt responses
480− ((result0, requests0), v') <- f (runRequesterT a0 (selectInt responses' 0)) $ fmapCheap (\(n, a) -> fmap ((,) n) $ runRequesterT a $ selectInt responses' n) na'
481− requests <- holdDyn (fmapCheap (IntMap.singleton 0) requests0) $ fmapCheap (\(n, (_, reqs)) -> fmapCheap (IntMap.singleton n) reqs) v'
482− return (result0, fmapCheap (fst . snd) v')
483−
484−{-# INLINE traverseIntMapWithKeyWithAdjustRequesterTWith #-}
485−traverseIntMapWithKeyWithAdjustRequesterTWith :: forall t request response m v v' p.
486− ( Reflex t
487− , MonadHold t m
488− , PatchTarget (p (Event t (IntMap (RequesterData request)))) ~ IntMap (Event t (IntMap (RequesterData request)))
489− , Patch (p (Event t (IntMap (RequesterData request))))
490− , Functor p
491− , MonadFix m
492− )
493− => ( (IntMap.Key -> (IntMap.Key, v) -> m (Event t (IntMap (RequesterData request)), v'))
494− -> IntMap (IntMap.Key, v)
495− -> Event t (p (IntMap.Key, v))
496− -> RequesterT t request response m (IntMap (Event t (IntMap (RequesterData request)), v'), Event t (p (Event t (IntMap (RequesterData request)), v')))
497− )
498− -> (p (Event t (IntMap (RequesterData request))) -> IntMap (Event t (IntMap (RequesterData request))))
499− -> (Incremental t (p (Event t (IntMap (RequesterData request)))) -> Event t (IntMap (IntMap (RequesterData request))))
500− -> (IntMap.Key -> v -> RequesterT t request response m v')
501− -> IntMap v
502− -> Event t (p v)
503− -> RequesterT t request response m (IntMap v', Event t (p v'))
504−traverseIntMapWithKeyWithAdjustRequesterTWith base patchNewElements mergePatchIncremental f dm0 dm' = do
505− rec response <- requesting' $ fmapCheap pack $ promptRequests `mappend` mergePatchIncremental requests --TODO: Investigate whether we can really get rid of the prompt stuff here
506− let responses :: EventSelectorInt t (IntMap (RequesterData response))
507− responses = fanInt $ fmapCheap unpack response
508− unpack :: Entry response Multi3 -> IntMap (IntMap (RequesterData response))
509− unpack = unEntry
510− pack :: IntMap (IntMap (RequesterData request)) -> Entry request Multi3
511− pack = Entry
512− f' :: IntMap.Key -> (Int, v) -> m (Event t (IntMap (RequesterData request)), v')
513− f' k (n, v) = do
514− (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ selectInt responses k --TODO: Instead of doing mapMaybeCheap, can we share a fanInt across all instances of a given key, or at least the ones that are adjacent in time?
515− return (fmapCheap (IntMap.singleton n) myRequests, result)
516− ndm' <- numberOccurrencesFrom 1 dm'
517− (children0, children') <- base f' (fmap ((,) 0) dm0) $ fmap (\(n, dm) -> fmap ((,) n) dm) ndm' --TODO: Avoid this somehow, probably by adding some sort of per-cohort information passing to Adjustable
518− let result0 = fmap snd children0
519− result' = fforCheap children' $ fmap snd
520− requests0 :: IntMap (Event t (IntMap (RequesterData request)))
521− requests0 = fmap fst children0
522− requests' :: Event t (p (Event t (IntMap (RequesterData request))))
523− requests' = fforCheap children' $ fmap fst
524− promptRequests :: Event t (IntMap (IntMap (RequesterData request)))
525− promptRequests = coincidence $ fmapCheap (mergeInt . patchNewElements) requests' --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
526− requests <- holdIncremental requests0 requests'
527− return (result0, result')
528−
529−{-# INLINE traverseDMapWithKeyWithAdjustRequesterTWith #-}
530−traverseDMapWithKeyWithAdjustRequesterTWith :: forall k t request response m v v' p p'.
531− ( GCompare k
532− , Reflex t
533− , MonadHold t m
534− , PatchTarget (p' (Some k) (Event t (IntMap (RequesterData request)))) ~ Map (Some k) (Event t (IntMap (RequesterData request)))
535− , Patch (p' (Some k) (Event t (IntMap (RequesterData request))))
536− , MonadFix m
537− )
538− => (forall k' v1 v2. GCompare k'
539− => (forall a. k' a -> v1 a -> m (v2 a))
540− -> DMap k' v1
541− -> Event t (p k' v1)
542− -> RequesterT t request response m (DMap k' v2, Event t (p k' v2))
543− )
544− -> (forall v1 v2. (forall a. v1 a -> v2 a) -> p k v1 -> p k v2)
545− -> (forall v1 v2. (forall a. v1 a -> v2) -> p k v1 -> p' (Some k) v2)
546− -> (forall v2. p' (Some k) v2 -> Map (Some k) v2)
547− -> (forall a. Incremental t (p' (Some k) (Event t a)) -> Event t (Map (Some k) a))
548− -> (forall a. k a -> v a -> RequesterT t request response m (v' a))
549− -> DMap k v
550− -> Event t (p k v)
551− -> RequesterT t request response m (DMap k v', Event t (p k v'))
552−traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchNewElements mergePatchIncremental f dm0 dm' = do
553− rec response <- requesting' $ fmapCheap pack $ promptRequests `mappend` mergePatchIncremental requests --TODO: Investigate whether we can really get rid of the prompt stuff here
554− let responses :: EventSelector t (Const2 (Some k) (IntMap (RequesterData response)))
555− responses = fanMap $ fmapCheap unpack response
556− unpack :: Entry response (Multi2 k) -> Map (Some k) (IntMap (RequesterData response))
557− unpack = unEntry
558− pack :: Map (Some k) (IntMap (RequesterData request)) -> Entry request (Multi2 k)
559− pack = Entry
560− f' :: forall a. k a -> Compose ((,) Int) v a -> m (Compose ((,) (Event t (IntMap (RequesterData request)))) v' a)
561− f' k (Compose (n, v)) = do
562− (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some k))
563− return $ Compose (fmapCheap (IntMap.singleton n) myRequests, result)
564− ndm' <- numberOccurrencesFrom 1 dm'
565− (children0, children') <- base f' (DMap.map (\v -> Compose (0, v)) dm0) $ fmap (\(n, dm) -> mapPatch (\v -> Compose (n, v)) dm) ndm'
566− let result0 = DMap.map (snd . getCompose) children0
567− result' = fforCheap children' $ mapPatch $ snd . getCompose
568− requests0 :: Map (Some k) (Event t (IntMap (RequesterData request)))
569− requests0 = weakenDMapWith (fst . getCompose) children0
570− requests' :: Event t (p' (Some k) (Event t (IntMap (RequesterData request))))
571− requests' = fforCheap children' $ weakenPatchWith $ fst . getCompose
572− promptRequests :: Event t (Map (Some k) (IntMap (RequesterData request)))
573− promptRequests = coincidence $ fmapCheap (mergeMap . patchNewElements) requests' --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
574− requests <- holdIncremental requests0 requests'
575− return (result0, result')
576−
577−data Decoder rawResponse response =
578− forall a. Decoder (RequesterDataKey a) (rawResponse -> response a)
579−
580−-- | Matches incoming responses with previously-sent requests
581−-- and uses the provided request "decoder" function to process
582−-- incoming responses.
583−matchResponsesWithRequests
584− :: forall t rawRequest rawResponse request response m.
585− ( MonadFix m
586− , MonadHold t m
587− , Reflex t
588− )
589− => (forall a. request a -> (rawRequest, rawResponse -> response a))
590− -- ^ Given a request (from 'Requester'), produces the wire format of the
591− -- request and a function used to process the associated response
592− -> Event t (RequesterData request)
593− -- ^ The outgoing requests
594− -> Event t (Int, rawResponse)
595− -- ^ The incoming responses, tagged by an identifying key
596− -> m ( Event t (Map Int rawRequest)
597− , Event t (RequesterData response)
598− )
599− -- ^ A map of outgoing wire-format requests and an event of responses keyed
600− -- by the 'RequesterData' key of the associated outgoing request
601−matchResponsesWithRequests f send recv = do
602− rec nextId <- hold 1 $ fmap (\(next, _, _) -> next) outgoing
603− waitingFor :: Incremental t (PatchMap Int (Decoder rawResponse response)) <-
604− holdIncremental mempty $ leftmost
605− [ fmap (\(_, outstanding, _) -> outstanding) outgoing
606− , snd <$> incoming
607− ]
608− let outgoing = processOutgoing nextId send
609− incoming = processIncoming waitingFor recv
610− return (fmap (\(_, _, rawReqs) -> rawReqs) outgoing, fst <$> incoming)
611− where
612− -- Tags each outgoing request with an identifying integer key
613− -- and returns the next available key, a map of response decoders
614− -- for requests for which there are outstanding responses, and the
615− -- raw requests to be sent out.
616− processOutgoing
617− :: Behavior t Int
618− -- The next available key
619− -> Event t (RequesterData request)
620− -- The outgoing request
621− -> Event t ( Int
622− , PatchMap Int (Decoder rawResponse response)
623− , Map Int rawRequest )
624− -- The new next-available-key, a map of requests expecting responses, and the tagged raw requests
625− processOutgoing nextId out = flip pushAlways out $ \dm -> do
626− oldNextId <- sample nextId
627− let (result, newNextId) = flip runState oldNextId $ forM (requesterDataToList dm) $ \(k :=> v) -> do
628− n <- get
629− put $ succ n
630− let (rawReq, rspF) = f v
631− return (n, rawReq, Decoder k rspF)
632− patchWaitingFor = PatchMap $ Map.fromList $
633− (\(n, _, dec) -> (n, Just dec)) <$> result
634− toSend = Map.fromList $ (\(n, rawReq, _) -> (n, rawReq)) <$> result
635− return (newNextId, patchWaitingFor, toSend)
636− -- Looks up the each incoming raw response in a map of response
637− -- decoders and returns the decoded response and a patch that can
638− -- be used to clear the ID of the consumed response out of the queue
639− -- of expected responses.
640− processIncoming
641− :: Incremental t (PatchMap Int (Decoder rawResponse response))
642− -- A map of outstanding expected responses
643− -> Event t (Int, rawResponse)
644− -- A incoming response paired with its identifying key
645− -> Event t (RequesterData response, PatchMap Int v)
646− -- The decoded response and a patch that clears the outstanding responses queue
647− processIncoming waitingFor inc = flip push inc $ \(n, rawRsp) -> do
648− wf <- sample $ currentIncremental waitingFor
649− case Map.lookup n wf of
650− Nothing -> return Nothing -- TODO How should lookup failures be handled here? They shouldn't ever happen..
651− Just (Decoder k rspF) -> do
652− let rsp = rspF rawRsp
653− return $ Just
654− ( singletonRequesterData k rsp
655− , PatchMap $ Map.singleton n Nothing
656− )
657−-}
19+import Reflex.Requester.Base.Internal
src/Reflex/Requester/Base/Internal.hsnew file+661
@@ -0,0 +1,661 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE CPP #-}
3+{-# LANGUAGE EmptyDataDecls #-}
4+{-# LANGUAGE ExistentialQuantification #-}
5+{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE GADTs #-}
7+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
8+{-# LANGUAGE MultiParamTypeClasses #-}
9+{-# LANGUAGE Rank2Types #-}
10+{-# LANGUAGE RecursiveDo #-}
11+{-# LANGUAGE ScopedTypeVariables #-}
12+{-# LANGUAGE StandaloneDeriving #-}
13+{-# LANGUAGE TypeFamilies #-}
14+{-# LANGUAGE TypeOperators #-}
15+{-# LANGUAGE UndecidableInstances #-}
16+{-# LANGUAGE InstanceSigs #-}
17+#ifdef USE_REFLEX_OPTIMIZER
18+{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
19+#endif
20+module Reflex.Requester.Base.Internal where
21+
22+import Reflex.Class
23+import Reflex.Adjustable.Class
24+import Reflex.Dynamic
25+import Reflex.Host.Class
26+import Reflex.PerformEvent.Class
27+import Reflex.PostBuild.Class
28+import Reflex.Requester.Class
29+import Reflex.TriggerEvent.Class
30+import Reflex.EventWriter.Base
31+import Reflex.EventWriter.Class
32+
33+import Control.Applicative (liftA2)
34+import Control.Monad.Exception
35+import Control.Monad.Identity
36+import Control.Monad.Primitive
37+import Control.Monad.Reader
38+import Control.Monad.Ref
39+import Control.Monad.State.Strict
40+import Data.Bits
41+import Data.Coerce
42+import Data.Dependent.Map (DMap, DSum (..))
43+import qualified Data.Dependent.Map as DMap
44+import Data.Functor.Compose
45+import Data.Functor.Misc
46+import Data.IntMap.Strict (IntMap)
47+import qualified Data.IntMap.Strict as IntMap
48+import Data.Map (Map)
49+import qualified Data.Map as Map
50+import Data.Monoid ((<>))
51+import Data.Proxy
52+import qualified Data.Semigroup as S
53+import Data.Some (Some(Some))
54+import Data.Type.Equality
55+import Data.Sequence (Seq)
56+import qualified Data.Sequence as Seq
57+import Data.TagMap (TagMap)
58+import qualified Data.TagMap as TagMap
59+import Reflex.FanTag
60+import Data.Unique.Tag.Local
61+import qualified Data.Unique.Tag as Global
62+import Data.GADT.Compare
63+import Data.Witherable
64+import Data.Foldable
65+
66+data RequestData ps request = forall s. RequestData !(TagGen ps s) !(Seq (RequestEnvelope s request))
67+data ResponseData ps response = forall s. ResponseData !(TagGen ps s) !(TagMap s response)
68+
69+traverseRequesterData :: forall m request response. Applicative m => (forall a. request a -> m (response a)) -> RequestData (PrimState m) request -> m (ResponseData (PrimState m) response)
70+traverseRequesterData f (RequestData tg es) = ResponseData tg . TagMap.fromList <$> wither g (toList es)
71+ where g (RequestEnvelope mt req) = case mt of
72+ Just t -> (\rsp -> Just $ t :=> rsp) <$> f req
73+ Nothing -> Nothing <$ f req
74+
75+runRequesterT :: forall t request response m a
76+ . ( Reflex t
77+ , PrimMonad m
78+ , MonadFix m
79+ )
80+ => RequesterT t request response m a
81+ -> Event t (ResponseData (PrimState m) response)
82+ -> m (a, Event t (RequestData (PrimState m) request))
83+runRequesterT (RequesterT a) wrappedResponses = withRequesterInternalT $ \(requests :: Event t (Seq (RequestEnvelope s request))) -> do
84+ (_, tg) <- RequesterInternalT ask
85+ result <- a
86+ let responses = fforMaybe wrappedResponses $ \(ResponseData tg' m) -> case tg `geq` tg' of
87+ Nothing -> Nothing --TODO: Warn somehow
88+ Just Refl -> Just m
89+ pure (responses, (result, fmapCheap (RequestData tg) requests))
90+
91+instance MonadTrans (RequesterInternalT s t request response) where
92+ lift = RequesterInternalT . lift . lift
93+
94+instance MonadTrans (RequesterT t request response) where
95+ lift a = RequesterT $ RequesterInternalT $ lift $ lift a
96+
97+-- | Run a 'RequesterT' action. The resulting 'Event' will fire whenever
98+-- requests are made, and responses should be provided in the input 'Event'.
99+-- The 'Tag' keys will be used to return the responses to the same place the
100+-- requests were issued.
101+withRequesterInternalT
102+ :: ( Reflex t
103+ , PrimMonad m
104+ , MonadFix m
105+ )
106+ => (forall s. Event t (Seq (RequestEnvelope s request)) -> RequesterInternalT s t request response m (Event t (TagMap s response), a))
107+ -> m a
108+withRequesterInternalT f = withTagGen $ \tg -> do
109+ rec let RequesterInternalT a = f requests
110+ ((responses, result), requests) <- runEventWriterT $ runReaderT a (fanTag responses, tg)
111+ pure result
112+
113+data RequestEnvelope s request = forall a. RequestEnvelope {-# UNPACK #-} !(Maybe (Tag s a)) !(request a)
114+
115+newtype RequesterT t (request :: * -> *) (response :: * -> *) m a = RequesterT { unRequesterT :: forall s. RequesterInternalT s t request response m a }
116+
117+instance Functor m => Functor (RequesterT t request response m) where
118+ fmap f (RequesterT x) = RequesterT $ fmap f x
119+
120+instance Monad m => Applicative (RequesterT t request response m) where
121+ pure x = RequesterT $ pure x
122+ RequesterT f <*> RequesterT x = RequesterT $ f <*> x
123+ liftA2 f (RequesterT a) (RequesterT b) = RequesterT $ liftA2 f a b
124+ RequesterT f <* RequesterT x = RequesterT $ f <* x
125+ RequesterT f *> RequesterT x = RequesterT $ f *> x
126+
127+instance Monad m => Monad (RequesterT t request response m) where
128+ return = pure
129+ RequesterT mx >>= f = RequesterT $ mx >>= \x -> case f x of
130+ RequesterT y -> y
131+
132+instance MonadFix m => MonadFix (RequesterT t request response m) where
133+ mfix f = RequesterT $ mfix $ \x -> case f x of
134+ RequesterT a -> a
135+
136+instance MonadIO m => MonadIO (RequesterT t request respnose m) where
137+ liftIO a = RequesterT $ liftIO a
138+
139+instance MonadException m => MonadException (RequesterT t request respnose m) where
140+ throw e = RequesterT $ throw e
141+
142+newtype RequesterInternalT s t request response m a = RequesterInternalT { unRequesterInternalT :: ReaderT (EventSelectorTag t s response, TagGen (PrimState m) s) (EventWriterT t (Seq (RequestEnvelope s request)) m) a }
143+ deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException)
144+
145+instance MonadSample t m => MonadSample t (RequesterT t request response m)
146+instance MonadHold t m => MonadHold t (RequesterT t request response m)
147+instance PostBuild t m => PostBuild t (RequesterT t request response m)
148+instance TriggerEvent t m => TriggerEvent t (RequesterT t request response m)
149+
150+instance PrimMonad m => PrimMonad (RequesterT t request response m) where
151+ type PrimState (RequesterT t request response m) = PrimState m
152+ primitive = lift . primitive
153+
154+-- TODO: Monoid and Semigroup can likely be derived once StateT has them.
155+instance (Monoid a, Monad m) => Monoid (RequesterT t request response m a) where
156+ mempty = pure mempty
157+ mappend = liftA2 mappend
158+
159+instance (S.Semigroup a, Monad m) => S.Semigroup (RequesterT t request response m a) where
160+ (<>) = liftA2 (S.<>)
161+
162+instance PerformEvent t m => PerformEvent t (RequesterT t request response m) where
163+ type Performable (RequesterT t request response m) = Performable m
164+ performEvent_ = lift . performEvent_
165+ performEvent = lift . performEvent
166+
167+instance MonadRef m => MonadRef (RequesterT t request response m) where
168+ type Ref (RequesterT t request response m) = Ref m
169+ newRef = lift . newRef
170+ readRef = lift . readRef
171+ writeRef r = lift . writeRef r
172+
173+instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (RequesterT t request response m) where
174+ newEventWithTrigger = lift . newEventWithTrigger
175+ newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
176+
177+instance MonadReader r m => MonadReader r (RequesterT t request response m) where
178+ ask = lift ask
179+ local f (RequesterT a) = RequesterT $ RequesterInternalT $ mapReaderT (mapEventWriterT $ local f) $ unRequesterInternalT a
180+ reader = lift . reader
181+
182+instance (Reflex t, PrimMonad m) => Requester t (RequesterT t request response m) where
183+ type Request (RequesterT t request response m) = request
184+ type Response (RequesterT t request response m) = response
185+ requesting e = RequesterT $ requesting e
186+ requesting_ e = RequesterT $ requesting_ e
187+
188+instance (Reflex t, PrimMonad m) => Requester t (RequesterInternalT s t request response m) where
189+ type Request (RequesterInternalT s t request response m) = request
190+ type Response (RequesterInternalT s t request response m) = response
191+ requesting e = RequesterInternalT $ do
192+ (s, tg) <- ask
193+ t <- lift $ lift $ newTag tg
194+ tellEvent $ fmapCheap (Seq.singleton . RequestEnvelope (Just t)) e
195+ pure $ selectTag s t
196+ requesting_ e = RequesterInternalT $ do
197+ tellEvent $ fmapCheap (Seq.singleton . RequestEnvelope Nothing) e
198+
199+instance Adjustable t m => Adjustable t (RequesterInternalT s t request response m)
200+
201+{-# INLINABLE runWithReplaceRequesterTWith #-}
202+runWithReplaceRequesterTWith :: forall m t request response a b. (Reflex t, MonadHold t m
203+ , MonadFix m
204+ )
205+ => (forall a' b'. m a' -> Event t (m b') -> RequesterT t request response m (a', Event t b'))
206+ -> RequesterT t request response m a
207+ -> Event t (RequesterT t request response m b)
208+ -> RequesterT t request response m (a, Event t b)
209+runWithReplaceRequesterTWith f (RequesterT a0) a' = RequesterT $ do
210+ pure undefined
211+
212+{-
213+import GHC.Exts (Any)
214+import Unsafe.Coerce
215+
216+--TODO: Make this module type-safe
217+
218+newtype TagMap (f :: * -> *) = TagMap (IntMap Any)
219+
220+newtype RequesterData f = RequesterData (TagMap (Entry f))
221+
222+data RequesterDataKey a where
223+ RequesterDataKey_Single :: {-# UNPACK #-} !(MyTag (Single a)) -> RequesterDataKey a
224+ RequesterDataKey_Multi :: {-# UNPACK #-} !(MyTag Multi) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a --TODO: Don't put a second Int here (or in the other Multis); use a single Int instead
225+ RequesterDataKey_Multi2 :: {-# UNPACK #-} !(MyTag (Multi2 k)) -> !(Some k) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
226+ RequesterDataKey_Multi3 :: {-# UNPACK #-} !(MyTag Multi3) -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
227+
228+singletonRequesterData :: RequesterDataKey a -> f a -> RequesterData f
229+singletonRequesterData rdk v = case rdk of
230+ RequesterDataKey_Single k -> RequesterData $ singletonTagMap k $ Entry v
231+ RequesterDataKey_Multi k k' k'' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ singletonRequesterData k'' v
232+ RequesterDataKey_Multi2 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ Map.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
233+ RequesterDataKey_Multi3 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
234+
235+requesterDataToList :: RequesterData f -> [DSum RequesterDataKey f]
236+requesterDataToList (RequesterData m) = do
237+ k :=> Entry e <- tagMapToList m
238+ case myKeyType k of
239+ MyTagType_Single -> return $ RequesterDataKey_Single k :=> e
240+ MyTagType_Multi -> do
241+ (k', e') <- IntMap.toList e
242+ k'' :=> e'' <- requesterDataToList e'
243+ return $ RequesterDataKey_Multi k k' k'' :=> e''
244+ MyTagType_Multi2 -> do
245+ (k', e') <- Map.toList e
246+ (k'', e'') <- IntMap.toList e'
247+ k''' :=> e''' <- requesterDataToList e''
248+ return $ RequesterDataKey_Multi2 k k' k'' k''' :=> e'''
249+ MyTagType_Multi3 -> do
250+ (k', e') <- IntMap.toList e
251+ (k'', e'') <- IntMap.toList e'
252+ k''' :=> e''' <- requesterDataToList e''
253+ return $ RequesterDataKey_Multi3 k k' k'' k''' :=> e'''
254+
255+singletonTagMap :: forall f a. MyTag a -> f a -> TagMap f
256+singletonTagMap (MyTag k) v = TagMap $ IntMap.singleton k $ (unsafeCoerce :: f a -> Any) v
257+
258+tagMapToList :: forall f. TagMap f -> [DSum MyTag f]
259+tagMapToList (TagMap m) = f <$> IntMap.toList m
260+ where f :: (Int, Any) -> DSum MyTag f
261+ f (k, v) = MyTag k :=> (unsafeCoerce :: Any -> f a) v
262+
263+traverseTagMapWithKey :: forall t f g. Applicative t => (forall a. MyTag a -> f a -> t (g a)) -> TagMap f -> t (TagMap g)
264+traverseTagMapWithKey f (TagMap m) = TagMap <$> IntMap.traverseWithKey g m
265+ where
266+ g :: Int -> Any -> t Any
267+ g k v = (unsafeCoerce :: g a -> Any) <$> f (MyTag k) ((unsafeCoerce :: Any -> f a) v)
268+
269+-- | Runs in reverse to accommodate for the fact that we accumulate it in reverse
270+traverseRequesterData :: forall m request response. Applicative m => (forall a. request a -> m (response a)) -> RequesterData request -> m (RequesterData response)
271+traverseRequesterData f (RequesterData m) = RequesterData <$> traverseTagMapWithKey go m --TODO: reverse this, since our tags are in reverse order
272+ where go :: forall x. MyTag x -> Entry request x -> m (Entry response x)
273+ go k (Entry request) = Entry <$> case myKeyType k of
274+ MyTagType_Single -> f request
275+ MyTagType_Multi -> traverse (traverseRequesterData f) request
276+ MyTagType_Multi2 -> traverse (traverse (traverseRequesterData f)) request
277+ MyTagType_Multi3 -> traverse (traverse (traverseRequesterData f)) request
278+
279+-- | 'traverseRequesterData' with its arguments flipped
280+forRequesterData :: forall request response m. Applicative m => RequesterData request -> (forall a. request a -> m (response a)) -> m (RequesterData response)
281+forRequesterData r f = traverseRequesterData f r
282+
283+data MyTagType :: * -> * where
284+ MyTagType_Single :: MyTagType (Single a)
285+ MyTagType_Multi :: MyTagType Multi
286+ MyTagType_Multi2 :: MyTagType (Multi2 k)
287+ MyTagType_Multi3 :: MyTagType Multi3
288+
289+myKeyType :: MyTag x -> MyTagType x
290+myKeyType (MyTag k) = case k .&. 0x3 of
291+ 0x0 -> unsafeCoerce MyTagType_Single
292+ 0x1 -> unsafeCoerce MyTagType_Multi
293+ 0x2 -> unsafeCoerce MyTagType_Multi2
294+ 0x3 -> unsafeCoerce MyTagType_Multi3
295+ t -> error $ "Reflex.Requester.Base.myKeyType: no such key type" <> show t
296+
297+data Single a
298+data Multi
299+data Multi2 (k :: * -> *)
300+data Multi3
301+
302+class MyTagTypeOffset x where
303+ myTagTypeOffset :: proxy x -> Int
304+
305+instance MyTagTypeOffset (Single a) where
306+ myTagTypeOffset _ = 0x0
307+
308+instance MyTagTypeOffset Multi where
309+ myTagTypeOffset _ = 0x1
310+
311+instance MyTagTypeOffset (Multi2 k) where
312+ myTagTypeOffset _ = 0x2
313+
314+instance MyTagTypeOffset Multi3 where
315+ myTagTypeOffset _ = 0x3
316+
317+type family EntryContents request a where
318+ EntryContents request (Single a) = request a
319+ EntryContents request Multi = IntMap (RequesterData request)
320+ EntryContents request (Multi2 k) = Map (Some k) (IntMap (RequesterData request))
321+ EntryContents request Multi3 = IntMap (IntMap (RequesterData request))
322+
323+newtype Entry request x = Entry { unEntry :: EntryContents request x }
324+
325+{-# INLINE singleEntry #-}
326+singleEntry :: f a -> Entry f (Single a)
327+singleEntry = Entry
328+
329+{-# INLINE multiEntry #-}
330+multiEntry :: IntMap (RequesterData f) -> Entry f Multi
331+multiEntry = Entry
332+
333+{-# INLINE unMultiEntry #-}
334+unMultiEntry :: Entry f Multi -> IntMap (RequesterData f)
335+unMultiEntry = unEntry
336+
337+-- | We use a hack here to pretend we have x ~ request a; we don't want to use a GADT, because GADTs (even with zero-size existential contexts) can't be newtypes
338+-- WARNING: This type should never be exposed. In particular, this is extremely unsound if a MyTag from one run of runRequesterT is ever compared against a MyTag from another
339+newtype MyTag x = MyTag Int deriving (Show, Eq, Ord, Enum)
340+
341+newtype MyTagWrap (f :: * -> *) x = MyTagWrap Int deriving (Show, Eq, Ord, Enum)
342+
343+{-# INLINE castMyTagWrap #-}
344+castMyTagWrap :: MyTagWrap f (Entry f x) -> MyTagWrap g (Entry g x)
345+castMyTagWrap = coerce
346+
347+instance GEq MyTag where
348+ (MyTag a) `geq` (MyTag b) =
349+ if a == b
350+ then Just $ unsafeCoerce Refl
351+ else Nothing
352+
353+instance GCompare MyTag where
354+ (MyTag a) `gcompare` (MyTag b) =
355+ case a `compare` b of
356+ LT -> GLT
357+ EQ -> unsafeCoerce GEQ
358+ GT -> GGT
359+
360+instance GEq (MyTagWrap f) where
361+ (MyTagWrap a) `geq` (MyTagWrap b) =
362+ if a == b
363+ then Just $ unsafeCoerce Refl
364+ else Nothing
365+
366+instance GCompare (MyTagWrap f) where
367+ (MyTagWrap a) `gcompare` (MyTagWrap b) =
368+ case a `compare` b of
369+ LT -> GLT
370+ EQ -> unsafeCoerce GEQ
371+ GT -> GGT
372+
373+data RequesterState t (request :: * -> *) = RequesterState
374+ { _requesterState_nextMyTag :: {-# UNPACK #-} !Int -- Starts at -4 and goes down by 4 each time, to accommodate two 'type' bits at the bottom
375+ , _requesterState_requests :: ![(Int, Event t Any)]
376+ }
377+
378+-- | A basic implementation of 'Requester'.
379+newtype RequesterT t request (response :: * -> *) m a = RequesterT { unRequesterT :: StateT (RequesterState t request) (ReaderT (EventSelectorInt t Any) m) a }
380+ deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException
381+-- MonadAsyncException can't be derived on ghc-8.0.1; we use base-4.9.1 as a proxy for ghc-8.0.2
382+#if MIN_VERSION_base(4,9,1)
383+ , MonadAsyncException
384+#endif
385+ )
386+
387+
388+-- | Run a 'RequesterT' action. The resulting 'Event' will fire whenever
389+-- requests are made, and responses should be provided in the input 'Event'.
390+-- The 'Tag' keys will be used to return the responses to the same place the
391+-- requests were issued.
392+runRequesterT :: (Reflex t, Monad m)
393+ => RequesterT t request response m a
394+ -> Event t (RequesterData response) --TODO: This DMap will be in reverse order, so we need to make sure the caller traverses it in reverse
395+ -> m (a, Event t (RequesterData request)) --TODO: we need to hide these 'MyTag's here, because they're unsafe to mix in the wild
396+runRequesterT (RequesterT a) responses = do
397+ (result, s) <- runReaderT (runStateT a $ RequesterState (-4) []) $ fanInt $
398+ coerceEvent responses
399+ return (result, fmapCheap (RequesterData . TagMap) $ mergeInt $ IntMap.fromDistinctAscList $ _requesterState_requests s)
400+
401+-- | Map a function over the request and response of a 'RequesterT'
402+withRequesterT
403+ :: (Reflex t, MonadFix m)
404+ => (forall x. req x -> req' x) -- ^ The function to map over the request
405+ -> (forall x. rsp' x -> rsp x) -- ^ The function to map over the response
406+ -> RequesterT t req rsp m a -- ^ The internal 'RequesterT' whose input and output will be transformed
407+ -> RequesterT t req' rsp' m a -- ^ The resulting 'RequesterT'
408+withRequesterT freq frsp child = do
409+ rec let rsp = fmap (runIdentity . traverseRequesterData (Identity . frsp)) rsp'
410+ (a, req) <- lift $ runRequesterT child rsp
411+ rsp' <- fmap (flip selectInt 0 . fanInt . fmapCheap unMultiEntry) $ requesting' $
412+ fmapCheap (multiEntry . IntMap.singleton 0) $ fmap (runIdentity . traverseRequesterData (Identity . freq)) req
413+ return a
414+
415+instance (Reflex t, Monad m) => Requester t (RequesterT t request response m) where
416+ type Request (RequesterT t request response m) = request
417+ type Response (RequesterT t request response m) = response
418+ requesting = fmap coerceEvent . responseFromTag . castMyTagWrap <=< tagRequest . (coerceEvent :: Event t (request a) -> Event t (Entry request (Single a)))
419+ requesting_ = void . tagRequest . fmapCheap singleEntry
420+
421+{-# INLINE tagRequest #-}
422+tagRequest :: forall m x t request response. (Monad m, MyTagTypeOffset x) => Event t (Entry request x) -> RequesterT t request response m (MyTagWrap request (Entry request x))
423+tagRequest req = do
424+ old <- RequesterT get
425+ let n = _requesterState_nextMyTag old .|. myTagTypeOffset (Proxy :: Proxy x)
426+ t = MyTagWrap n
427+ RequesterT $ put $ RequesterState
428+ { _requesterState_nextMyTag = _requesterState_nextMyTag old - 0x4
429+ , _requesterState_requests = (n, (unsafeCoerce :: Event t (Entry request x) -> Event t Any) req) : _requesterState_requests old
430+ }
431+ return t
432+
433+{-# INLINE responseFromTag #-}
434+responseFromTag :: Monad m => MyTagWrap response (Entry response x) -> RequesterT t request response m (Event t (Entry response x))
435+responseFromTag (MyTagWrap t) = do
436+ responses :: EventSelectorInt t Any <- RequesterT ask
437+ return $ (unsafeCoerce :: Event t Any -> Event t (Entry response x)) $ selectInt responses t
438+
439+instance MonadTrans (RequesterT t request response) where
440+ lift = RequesterT . lift . lift
441+
442+instance PerformEvent t m => PerformEvent t (RequesterT t request response m) where
443+ type Performable (RequesterT t request response m) = Performable m
444+ performEvent_ = lift . performEvent_
445+ performEvent = lift . performEvent
446+
447+instance MonadRef m => MonadRef (RequesterT t request response m) where
448+ type Ref (RequesterT t request response m) = Ref m
449+ newRef = lift . newRef
450+ readRef = lift . readRef
451+ writeRef r = lift . writeRef r
452+
453+instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (RequesterT t request response m) where
454+ newEventWithTrigger = lift . newEventWithTrigger
455+ newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
456+
457+instance MonadReader r m => MonadReader r (RequesterT t request response m) where
458+ ask = lift ask
459+ local f (RequesterT a) = RequesterT $ mapStateT (mapReaderT $ local f) a
460+ reader = lift . reader
461+
462+instance (Reflex t, Adjustable t m, MonadHold t m, MonadFix m) => Adjustable t (RequesterT t request response m) where
463+ runWithReplace = runWithReplaceRequesterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm'
464+ traverseIntMapWithKeyWithAdjust = traverseIntMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseIntMapWithKeyWithAdjust f dm0 dm') patchIntMapNewElementsMap mergeIntIncremental
465+ {-# INLINABLE traverseDMapWithKeyWithAdjust #-}
466+ traverseDMapWithKeyWithAdjust = traverseDMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjust f dm0 dm') mapPatchDMap weakenPatchDMapWith patchMapNewElementsMap mergeMapIncremental
467+ traverseDMapWithKeyWithAdjustWithMove = traverseDMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjustWithMove f dm0 dm') mapPatchDMapWithMove weakenPatchDMapWithMoveWith patchMapWithMoveNewElementsMap mergeMapIncrementalWithMove
468+
469+requesting' :: (MyTagTypeOffset x, Monad m) => Event t (Entry request x) -> RequesterT t request response m (Event t (Entry response x))
470+requesting' = responseFromTag . castMyTagWrap <=< tagRequest
471+
472+{-# INLINABLE runWithReplaceRequesterTWith #-}
473+runWithReplaceRequesterTWith :: forall m t request response a b. (Reflex t, MonadHold t m
474+ , MonadFix m
475+ )
476+ => (forall a' b'. m a' -> Event t (m b') -> RequesterT t request response m (a', Event t b'))
477+ -> RequesterT t request response m a
478+ -> Event t (RequesterT t request response m b)
479+ -> RequesterT t request response m (a, Event t b)
480+runWithReplaceRequesterTWith f a0 a' = do
481+ rec na' <- numberOccurrencesFrom 1 a'
482+ responses <- fmap (fmapCheap unMultiEntry) $ requesting' $ fmapCheap multiEntry $ switchPromptlyDyn requests --TODO: Investigate whether we can really get rid of the prompt stuff here
483+ let responses' = fanInt responses
484+ ((result0, requests0), v') <- f (runRequesterT a0 (selectInt responses' 0)) $ fmapCheap (\(n, a) -> fmap ((,) n) $ runRequesterT a $ selectInt responses' n) na'
485+ requests <- holdDyn (fmapCheap (IntMap.singleton 0) requests0) $ fmapCheap (\(n, (_, reqs)) -> fmapCheap (IntMap.singleton n) reqs) v'
486+ return (result0, fmapCheap (fst . snd) v')
487+
488+{-# INLINE traverseIntMapWithKeyWithAdjustRequesterTWith #-}
489+traverseIntMapWithKeyWithAdjustRequesterTWith :: forall t request response m v v' p.
490+ ( Reflex t
491+ , MonadHold t m
492+ , PatchTarget (p (Event t (IntMap (RequesterData request)))) ~ IntMap (Event t (IntMap (RequesterData request)))
493+ , Patch (p (Event t (IntMap (RequesterData request))))
494+ , Functor p
495+ , MonadFix m
496+ )
497+ => ( (IntMap.Key -> (IntMap.Key, v) -> m (Event t (IntMap (RequesterData request)), v'))
498+ -> IntMap (IntMap.Key, v)
499+ -> Event t (p (IntMap.Key, v))
500+ -> RequesterT t request response m (IntMap (Event t (IntMap (RequesterData request)), v'), Event t (p (Event t (IntMap (RequesterData request)), v')))
501+ )
502+ -> (p (Event t (IntMap (RequesterData request))) -> IntMap (Event t (IntMap (RequesterData request))))
503+ -> (Incremental t (p (Event t (IntMap (RequesterData request)))) -> Event t (IntMap (IntMap (RequesterData request))))
504+ -> (IntMap.Key -> v -> RequesterT t request response m v')
505+ -> IntMap v
506+ -> Event t (p v)
507+ -> RequesterT t request response m (IntMap v', Event t (p v'))
508+traverseIntMapWithKeyWithAdjustRequesterTWith base patchNewElements mergePatchIncremental f dm0 dm' = do
509+ rec response <- requesting' $ fmapCheap pack $ promptRequests `mappend` mergePatchIncremental requests --TODO: Investigate whether we can really get rid of the prompt stuff here
510+ let responses :: EventSelectorInt t (IntMap (RequesterData response))
511+ responses = fanInt $ fmapCheap unpack response
512+ unpack :: Entry response Multi3 -> IntMap (IntMap (RequesterData response))
513+ unpack = unEntry
514+ pack :: IntMap (IntMap (RequesterData request)) -> Entry request Multi3
515+ pack = Entry
516+ f' :: IntMap.Key -> (Int, v) -> m (Event t (IntMap (RequesterData request)), v')
517+ f' k (n, v) = do
518+ (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ selectInt responses k --TODO: Instead of doing mapMaybeCheap, can we share a fanInt across all instances of a given key, or at least the ones that are adjacent in time?
519+ return (fmapCheap (IntMap.singleton n) myRequests, result)
520+ ndm' <- numberOccurrencesFrom 1 dm'
521+ (children0, children') <- base f' (fmap ((,) 0) dm0) $ fmap (\(n, dm) -> fmap ((,) n) dm) ndm' --TODO: Avoid this somehow, probably by adding some sort of per-cohort information passing to Adjustable
522+ let result0 = fmap snd children0
523+ result' = fforCheap children' $ fmap snd
524+ requests0 :: IntMap (Event t (IntMap (RequesterData request)))
525+ requests0 = fmap fst children0
526+ requests' :: Event t (p (Event t (IntMap (RequesterData request))))
527+ requests' = fforCheap children' $ fmap fst
528+ promptRequests :: Event t (IntMap (IntMap (RequesterData request)))
529+ promptRequests = coincidence $ fmapCheap (mergeInt . patchNewElements) requests' --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
530+ requests <- holdIncremental requests0 requests'
531+ return (result0, result')
532+
533+{-# INLINE traverseDMapWithKeyWithAdjustRequesterTWith #-}
534+traverseDMapWithKeyWithAdjustRequesterTWith :: forall k t request response m v v' p p'.
535+ ( GCompare k
536+ , Reflex t
537+ , MonadHold t m
538+ , PatchTarget (p' (Some k) (Event t (IntMap (RequesterData request)))) ~ Map (Some k) (Event t (IntMap (RequesterData request)))
539+ , Patch (p' (Some k) (Event t (IntMap (RequesterData request))))
540+ , MonadFix m
541+ )
542+ => (forall k' v1 v2. GCompare k'
543+ => (forall a. k' a -> v1 a -> m (v2 a))
544+ -> DMap k' v1
545+ -> Event t (p k' v1)
546+ -> RequesterT t request response m (DMap k' v2, Event t (p k' v2))
547+ )
548+ -> (forall v1 v2. (forall a. v1 a -> v2 a) -> p k v1 -> p k v2)
549+ -> (forall v1 v2. (forall a. v1 a -> v2) -> p k v1 -> p' (Some k) v2)
550+ -> (forall v2. p' (Some k) v2 -> Map (Some k) v2)
551+ -> (forall a. Incremental t (p' (Some k) (Event t a)) -> Event t (Map (Some k) a))
552+ -> (forall a. k a -> v a -> RequesterT t request response m (v' a))
553+ -> DMap k v
554+ -> Event t (p k v)
555+ -> RequesterT t request response m (DMap k v', Event t (p k v'))
556+traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchNewElements mergePatchIncremental f dm0 dm' = do
557+ rec response <- requesting' $ fmapCheap pack $ promptRequests `mappend` mergePatchIncremental requests --TODO: Investigate whether we can really get rid of the prompt stuff here
558+ let responses :: EventSelector t (Const2 (Some k) (IntMap (RequesterData response)))
559+ responses = fanMap $ fmapCheap unpack response
560+ unpack :: Entry response (Multi2 k) -> Map (Some k) (IntMap (RequesterData response))
561+ unpack = unEntry
562+ pack :: Map (Some k) (IntMap (RequesterData request)) -> Entry request (Multi2 k)
563+ pack = Entry
564+ f' :: forall a. k a -> Compose ((,) Int) v a -> m (Compose ((,) (Event t (IntMap (RequesterData request)))) v' a)
565+ f' k (Compose (n, v)) = do
566+ (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some k))
567+ return $ Compose (fmapCheap (IntMap.singleton n) myRequests, result)
568+ ndm' <- numberOccurrencesFrom 1 dm'
569+ (children0, children') <- base f' (DMap.map (\v -> Compose (0, v)) dm0) $ fmap (\(n, dm) -> mapPatch (\v -> Compose (n, v)) dm) ndm'
570+ let result0 = DMap.map (snd . getCompose) children0
571+ result' = fforCheap children' $ mapPatch $ snd . getCompose
572+ requests0 :: Map (Some k) (Event t (IntMap (RequesterData request)))
573+ requests0 = weakenDMapWith (fst . getCompose) children0
574+ requests' :: Event t (p' (Some k) (Event t (IntMap (RequesterData request))))
575+ requests' = fforCheap children' $ weakenPatchWith $ fst . getCompose
576+ promptRequests :: Event t (Map (Some k) (IntMap (RequesterData request)))
577+ promptRequests = coincidence $ fmapCheap (mergeMap . patchNewElements) requests' --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
578+ requests <- holdIncremental requests0 requests'
579+ return (result0, result')
580+
581+data Decoder rawResponse response =
582+ forall a. Decoder (RequesterDataKey a) (rawResponse -> response a)
583+
584+-- | Matches incoming responses with previously-sent requests
585+-- and uses the provided request "decoder" function to process
586+-- incoming responses.
587+matchResponsesWithRequests
588+ :: forall t rawRequest rawResponse request response m.
589+ ( MonadFix m
590+ , MonadHold t m
591+ , Reflex t
592+ )
593+ => (forall a. request a -> (rawRequest, rawResponse -> response a))
594+ -- ^ Given a request (from 'Requester'), produces the wire format of the
595+ -- request and a function used to process the associated response
596+ -> Event t (RequesterData request)
597+ -- ^ The outgoing requests
598+ -> Event t (Int, rawResponse)
599+ -- ^ The incoming responses, tagged by an identifying key
600+ -> m ( Event t (Map Int rawRequest)
601+ , Event t (RequesterData response)
602+ )
603+ -- ^ A map of outgoing wire-format requests and an event of responses keyed
604+ -- by the 'RequesterData' key of the associated outgoing request
605+matchResponsesWithRequests f send recv = do
606+ rec nextId <- hold 1 $ fmap (\(next, _, _) -> next) outgoing
607+ waitingFor :: Incremental t (PatchMap Int (Decoder rawResponse response)) <-
608+ holdIncremental mempty $ leftmost
609+ [ fmap (\(_, outstanding, _) -> outstanding) outgoing
610+ , snd <$> incoming
611+ ]
612+ let outgoing = processOutgoing nextId send
613+ incoming = processIncoming waitingFor recv
614+ return (fmap (\(_, _, rawReqs) -> rawReqs) outgoing, fst <$> incoming)
615+ where
616+ -- Tags each outgoing request with an identifying integer key
617+ -- and returns the next available key, a map of response decoders
618+ -- for requests for which there are outstanding responses, and the
619+ -- raw requests to be sent out.
620+ processOutgoing
621+ :: Behavior t Int
622+ -- The next available key
623+ -> Event t (RequesterData request)
624+ -- The outgoing request
625+ -> Event t ( Int
626+ , PatchMap Int (Decoder rawResponse response)
627+ , Map Int rawRequest )
628+ -- The new next-available-key, a map of requests expecting responses, and the tagged raw requests
629+ processOutgoing nextId out = flip pushAlways out $ \dm -> do
630+ oldNextId <- sample nextId
631+ let (result, newNextId) = flip runState oldNextId $ forM (requesterDataToList dm) $ \(k :=> v) -> do
632+ n <- get
633+ put $ succ n
634+ let (rawReq, rspF) = f v
635+ return (n, rawReq, Decoder k rspF)
636+ patchWaitingFor = PatchMap $ Map.fromList $
637+ (\(n, _, dec) -> (n, Just dec)) <$> result
638+ toSend = Map.fromList $ (\(n, rawReq, _) -> (n, rawReq)) <$> result
639+ return (newNextId, patchWaitingFor, toSend)
640+ -- Looks up the each incoming raw response in a map of response
641+ -- decoders and returns the decoded response and a patch that can
642+ -- be used to clear the ID of the consumed response out of the queue
643+ -- of expected responses.
644+ processIncoming
645+ :: Incremental t (PatchMap Int (Decoder rawResponse response))
646+ -- A map of outstanding expected responses
647+ -> Event t (Int, rawResponse)
648+ -- A incoming response paired with its identifying key
649+ -> Event t (RequesterData response, PatchMap Int v)
650+ -- The decoded response and a patch that clears the outstanding responses queue
651+ processIncoming waitingFor inc = flip push inc $ \(n, rawRsp) -> do
652+ wf <- sample $ currentIncremental waitingFor
653+ case Map.lookup n wf of
654+ Nothing -> return Nothing -- TODO How should lookup failures be handled here? They shouldn't ever happen..
655+ Just (Decoder k rspF) -> do
656+ let rsp = rspF rawRsp
657+ return $ Just
658+ ( singletonRequesterData k rsp
659+ , PatchMap $ Map.singleton n Nothing
660+ )
661+-}