@@ -15,26 +15,19 @@ module Build
1515 , useOld
1616 ) where
1717
18- import Algebra.Graph.AdjacencyIntMap ( AdjacencyIntMap
19- , fromAdjacencyIntSets
20- , induce
21- , postIntSet
22- , transitiveClosure
23-
24- )
25- import Algebra.Graph.AdjacencyIntMap.Algorithm
26- ( topSort )
2718import Barbies
28- import Control.Monad
2919import Control.Monad.Fix
3020import Control.Monad.Trans.Class
3121import Control.Monad.Trans.Reader
3222import Control.Monad.Trans.State
3323import Data.Bifunctor
24+ import Data.Bool
3425import Data.Coerce ( coerce )
3526import Data.Dependent.Map ( DMap )
3627import qualified Data.Dependent.Map as DMap
3728import Data.Dependent.Sum
29+ import Data.Foldable
30+ import Data.Functor.Compose
3831import Data.Functor.Identity
3932import Data.Functor.Product
4033import Data.GADT.Compare ( GCompare (.. )
@@ -45,15 +38,11 @@ import qualified Data.IntMap as Map
4538import Data.IntMap.Strict ( IntMap )
4639import qualified Data.IntSet as Set
4740import Data.IntSet ( IntSet )
48- import Data.List ( intercalate
49- )
41+ import Data.List ( intercalate )
42+ import Data.Maybe
5043import Data.Some ( Some (Some ) )
5144import Data.Type.Equality ( (:~:) (Refl ) )
5245import Unsafe.Coerce ( unsafeCoerce )
53- import Data.Functor.Compose
54- import Data.Bool
55- import Data.Foldable
56- import Data.Maybe
5746
5847newtype Ref s a = Ref { unRef :: Int }
5948 deriving (Show )
@@ -70,12 +59,11 @@ instance GCompare (Ref s) where
7059 Refl -> GEQ
7160 GT -> GGT
7261
73-
7462data Action s a where
7563 Pure :: a -> Action s a
7664 Ap :: Action s (a -> b ) -> Action s a -> Action s b
7765 FMap :: (a -> b ) -> Action s a -> Action s b
78- -- This has to be lazy so that the MonadFix instance for Actions is useful
66+ -- These have to be lazy so that the MonadFix instance for Actions is useful
7967 UseRef :: Cond a -> ~ (Ref s a ) -> Action s a
8068 UseOldRef :: ~ (Ref s a ) -> Action s (Maybe a )
8169
@@ -148,28 +136,22 @@ initialActionState = ActionsState { asNextRef = 0
148136 , asNames = mempty
149137 }
150138
151- sortRefs
152- :: AdjacencyIntMap
153- -> IntSet
154- -> ActionsState s m
155- -> [DSum (Ref s ) (LookupRef s m )]
156- sortRefs graph initInts ActionsState {.. } =
157- let reachable =
158- let t = transitiveClosure graph
159- in Set. unions
160- (initInts : [ postIntSet i t | i <- Set. toList initInts ])
161- filtered = induce (`Set.member` reachable) graph
162- sorted = reverse $ case topSort filtered of
163- Left _ -> error " cycle in graph"
164- Right r -> r
165- acts = DMap. toAscList asCreate
166- in (acts !! ) <$> sorted
167-
139+ -- |
140+ --
141+ -- @
142+ -- {-# language ApplicativeDo #-}
143+ -- foo myOtherRef = do
144+ -- myDependency <- 'use' myOtherRef
145+ -- pure $ do
146+ -- some action using myDependency
147+ -- @
168148create
169149 :: forall m a s
170150 . Monad m
171151 => String
152+ -- ^ Name of node when rendered with 'actionsGraph'
172153 -> Action s (m a )
154+ -- ^ The dependencies of this action, and the action itself
173155 -> Actions s m (Ref s a )
174156create name act = do
175157 r <- newRef @ s @ m @ a
@@ -190,67 +172,34 @@ create name act = do
190172unCondDeps :: DMap (Ref s ) f -> IntSet
191173unCondDeps = Set. fromList . fmap (\ (Some (Ref r)) -> r) . DMap. keys
192174
193- makeNew
194- :: (Foldable t , Monad m )
195- => t (DSum (Ref s ) (LookupRef s m ))
196- -> (DMap (Ref s ) Identity -> b )
197- -> m b
198- makeNew sorted fromResolved = do
199- resolved <- foldM
200- (\ done (r :=> m) -> do
201- m' <- runLookupRef mempty done m
202- pure $ DMap. insert r (Identity m') done
203- )
204- mempty
205- sorted
206- pure $ fromResolved resolved
175+ ----------------------------------------------------------------
176+ -- Consuming 'Actions'
177+ ----------------------------------------------------------------
207178
179+ -- | Consume an 'Actions' and create the specified structure
208180runActions
209- :: (Monad m , TraversableB f )
181+ :: (Monad m , TraversableB f , ApplicativeB f )
210182 => (forall s . Actions s m (f (Ref s )))
211183 -> m (f Identity )
212- runActions (Actions c) =
213- let (rs, s@ ActionsState {.. }) = runState c initialActionState
214- needed = bfoldMap (Set. singleton . unRef) rs
215- graph =
216- fromAdjacencyIntSets
217- . fmap (fmap unCondDeps)
218- . Map. toList
219- $ asDepends
220- sorted = sortRefs graph needed s
221- fromResolved resolved =
222- runIdentity
223- . runLookupRef mempty resolved
224- . btraverse (fmap Identity . lookupRef)
225- $ rs
226- in makeNew sorted fromResolved
184+ runActions a = snd (runActionsWithRecreator a)
227185
186+ type Recreator m f = f DoRecreate -> f Identity -> m (f Identity )
187+
188+ data DoRecreate a = DoRecreate | DoNotRecreate
189+
190+ -- | Consume an 'Actions' and create the specified structure, also return a
191+ -- function to run the creation program again selectivly regenerating elements
228192runActionsWithRecreator
229193 :: forall m f
230194 . (Monad m , TraversableB f , ApplicativeB f )
231195 => (forall s . Actions s m (f (Ref s )))
232196 -> (Recreator m f , m (f Identity ))
233197runActionsWithRecreator (Actions c) =
234198 let
235- (rs, s@ ActionsState {.. }) = runState c initialActionState
236- needed = bfoldMap (Set. singleton . unRef) rs
237- graph =
238- fromAdjacencyIntSets . fmap (fmap unCondDeps) . Map. toList $ asDepends
239- sorted = sortRefs graph needed s
240- fromResolved oldMap resolved =
241- runIdentity
242- . runLookupRef oldMap resolved
243- . btraverse (fmap Identity . lookupRef)
244- $ rs
245-
246- reverseDeps :: DMap (Ref () ) CondDependees
247- reverseDeps = DMap. fromListWithKey
248- (const (<>) )
249- [ childRef :=> CondDependees [(p, cond)]
250- | (p, children) <- Map. toList asDepends
251- , (childRef :=> cond) <- DMap. toList children
252- ]
199+ (rs, ActionsState {.. }) = runState c initialActionState
253200
201+ -- Get ref from oldRefs, if it isn't there (because it wasn't persisted in
202+ -- the ref set) then regenerate it.
254203 realiseOldRef
255204 :: forall a
256205 . RefMap ()
@@ -260,19 +209,23 @@ runActionsWithRecreator (Actions c) =
260209 Just v -> pure v
261210 Nothing -> Identity <$> realiseRef (Just oldRefs) ref
262211
212+ -- Ensure that a ref has been generated, if it hasn't already been
213+ -- generated then make sure that its direct dependencies have been realised
214+ -- before creating it.
263215 realiseRef
264216 :: forall a
265- . Maybe ( RefMap () )
217+ . Maybe (RefMap () )
266218 -> Ref () a
267219 -> StateT (RefMap () , IntSet ) m a
268220 realiseRef oldRefsMb ref = do
269221 (refsWeHave, foundDirty) <- get
270222 case DMap. lookup ref refsWeHave of
271223 Just v -> pure (runIdentity v)
272224 Nothing
273- | unRef ref `Set.notMember` foundDirty, Just oldRefs <- oldRefsMb, Just r <- DMap. lookup
274- ref
275- oldRefs -> do
225+ | unRef ref `Set.notMember` foundDirty
226+ , Just oldRefs <- oldRefsMb
227+ , Just r <- DMap. lookup ref oldRefs
228+ -> do
276229 modify' (first $ DMap. insert ref r)
277230 pure $ runIdentity r
278231 Nothing -> do
@@ -285,34 +238,43 @@ runActionsWithRecreator (Actions c) =
285238 case oldRefsMb of
286239 Nothing -> pure ()
287240 Just oldRefs ->
288- for_ (Set. toList oldDeps)
289- $ realiseOldRef oldRefs
290- . Ref
241+ for_ (Set. toList oldDeps) $ realiseOldRef oldRefs . Ref
291242
292243 -- Then create this value
293244 let ourCreate =
294245 DMap. findWithDefault (error " missing ref creator" ) ref asCreate
295246 newRefs <- gets fst
296- r <- lift $ runLookupRef (fromMaybe mempty oldRefsMb) newRefs ourCreate
247+ r <- lift
248+ $ runLookupRef (fromMaybe mempty oldRefsMb) newRefs ourCreate
297249 modify' (first $ DMap. insert ref (Identity r))
298250 pure r
299251
300- regenRef
301- :: Maybe (RefMap () ) -> Ref () a -> StateT (RefMap () , IntSet ) m (Identity a )
252+ -- A map from references to the ones which depend on them, along with
253+ -- the condition for regeneration
254+ reverseDeps :: DMap (Ref () ) CondDependees
255+ reverseDeps = DMap. fromListWithKey
256+ (const (<>) )
257+ [ childRef :=> CondDependees [(p, cond)]
258+ | (p, children) <- Map. toList asDepends
259+ , (childRef :=> cond) <- DMap. toList children
260+ ]
261+
262+ -- Realise a ref, and mark its children as dirty if their condition says
263+ -- so.
264+ regenRef :: Maybe (RefMap () ) -> Ref () a -> StateT (RefMap () , IntSet ) m a
302265 regenRef oldRefs ref = do
303266 r <- realiseRef oldRefs ref
304267 -- Mark its dependees as dirty if they fail the condition
305- let CondDependees dependees =
306- DMap. findWithDefault mempty ref reverseDeps
307- dirtyDependees = Set. fromList
268+ let CondDependees dependees = DMap. findWithDefault mempty ref reverseDeps
269+ dirtyDependees = Set. fromList
308270 [ d
309271 | (d, Cond cond) <- dependees
310272 , case DMap. lookup ref =<< oldRefs of
311273 Nothing -> True
312274 Just (Identity oldR) -> cond oldR r
313275 ]
314276 modify' $ second (Set. union dirtyDependees)
315- pure $ Identity r
277+ pure r
316278
317279 recreate dirty old = do
318280 let initialDirtyRefs = bfoldMap
@@ -328,27 +290,24 @@ runActionsWithRecreator (Actions c) =
328290 flip evalStateT (mempty , initialDirtyRefs) $ btraverse
329291 (\ case
330292 -- We have been explicitly asked to recreate this one
331- Pair DoRecreate (Pair _ ref) -> regenRef (Just oldRefs) ref
293+ Pair DoRecreate (Pair _ ref) ->
294+ Identity <$> regenRef (Just oldRefs) ref
332295 Pair DoNotRecreate (Pair oldValue ref) -> do
333296 foundDirty <- gets snd
334297 if unRef ref `Set.member` foundDirty
335- then regenRef (Just oldRefs) ref
298+ then Identity <$> regenRef (Just oldRefs) ref
336299 else pure oldValue
337300 )
338301 (bzip dirty (bzip old rs))
339302
340303 createNew = do
341- flip evalStateT mempty $ btraverse (regenRef mempty ) rs
304+ flip evalStateT mempty $ btraverse (fmap Identity . realiseRef mempty ) rs
342305 in
343306 (recreate, createNew)
344307
345308newtype CondDependees a = CondDependees [(Int , Cond a )]
346309 deriving newtype (Semigroup , Monoid )
347310
348- type Recreator m f = f DoRecreate -> f Identity -> m (f Identity )
349-
350- data DoRecreate a = DoRecreate | DoNotRecreate
351-
352311-- | Generate a graphviz description for this set of actions
353312--
354313-- Dependencies on old values are shown with dotted lines
0 commit comments