Skip to content

Commit cfb9f8e

Browse files
Merge #875 Implement Monad{Thunk,Value}F through composition
2 parents cdcd82c + 7a91cf9 commit cfb9f8e

File tree

3 files changed

+103
-118
lines changed

3 files changed

+103
-118
lines changed

src/Nix/Standard.hs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -267,21 +267,15 @@ instance
267267
)
268268
-> StdValue m
269269
-> m r
270-
demandF f v =
271-
free
272-
(f <=< demand <=< force)
273-
(const $ f v)
274-
v
270+
demandF f = f <=< demand
275271

276272
informF
277273
:: ( m (StdValue m)
278274
-> m (StdValue m)
279275
)
280276
-> StdValue m
281277
-> m (StdValue m)
282-
-- 2021-02-27: NOTE: Switch to `further` and `inform`. Probably just informF f = f <=< inform
283-
informF f (Pure t) = Pure <$> furtherF f t
284-
informF f (Free v) = Free <$> bindNValue' id (informF f) v
278+
informF f = f . inform
285279

286280

287281
{------------------------------------------------------------------------}

src/Nix/Thunk/Basic.hs

Lines changed: 100 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ module Nix.Thunk.Basic
1616
, MonadBasicThunk
1717
) where
1818

19-
import Control.Exception hiding ( catch )
20-
import Control.Monad.Catch
21-
19+
import Control.Exception ( SomeException )
20+
import Control.Monad ( (<=<) )
21+
import Control.Monad.Catch ( MonadCatch(..)
22+
, MonadThrow(throwM)
23+
)
2224
import Nix.Thunk
2325
import Nix.Var
24-
import Nix.Utils ( bool )
26+
import Nix.Utils ( bool )
2527

2628
data Deferred m v = Deferred (m v) | Computed v
2729
deriving (Functor, Foldable, Traversable)
@@ -45,139 +47,128 @@ instance (MonadBasicThunk m, MonadCatch m)
4547
thunkId (Thunk n _ _) = n
4648

4749
thunk :: m v -> m (NThunkF m v)
48-
thunk = buildThunk
50+
thunk action =
51+
do
52+
freshThunkId <- freshId
53+
Thunk freshThunkId <$> newVar False <*> newVar (Deferred action)
4954

5055
queryM :: m v -> NThunkF m v -> m v
51-
queryM = queryThunk
56+
queryM n (Thunk _ active ref) =
57+
do
58+
thunkIsAvaliable <- not <$> atomicModifyVar active (True, )
59+
bool
60+
n
61+
go
62+
thunkIsAvaliable
63+
where
64+
go = do
65+
eres <- readVar ref
66+
res <-
67+
case eres of
68+
Computed v -> pure v
69+
Deferred _mv -> n
70+
_ <- atomicModifyVar active (False, )
71+
pure res
5272

5373
force :: NThunkF m v -> m v
54-
force = forceThunk
74+
force (Thunk n active ref) =
75+
do
76+
eres <- readVar ref
77+
case eres of
78+
Computed v -> pure v
79+
Deferred action ->
80+
do
81+
nowActive <- atomicModifyVar active (True, )
82+
bool
83+
(do
84+
v <- catch action $ \(e :: SomeException) ->
85+
do
86+
_ <- atomicModifyVar active (False, )
87+
throwM e
88+
writeVar ref (Computed v)
89+
_ <- atomicModifyVar active (False, )
90+
pure v
91+
)
92+
(throwM $ ThunkLoop $ show n)
93+
nowActive
5594

5695
forceEff :: NThunkF m v -> m v
57-
forceEff = forceEffects
96+
forceEff (Thunk _ active ref) =
97+
do
98+
nowActive <- atomicModifyVar active (True, )
99+
bool
100+
(do
101+
eres <- readVar ref
102+
case eres of
103+
Computed v -> pure v
104+
Deferred action ->
105+
do
106+
v <- action
107+
writeVar ref (Computed v)
108+
_ <- atomicModifyVar active (False, )
109+
pure v
110+
)
111+
(pure $ error "Loop detected")
112+
nowActive
58113

59114
further :: NThunkF m v -> m (NThunkF m v)
60-
further = furtherThunk
61-
62-
63-
-- ** Specialization barrier
64-
65-
-- Since Kleisly functors, ad-hoc polymorphism of type classes has computational cost.
66-
-- Especially when one also exports those functions.
67-
-- So here - helping the compiler to specialize functions.
68-
69-
buildThunk :: MonadBasicThunk m => m v -> m (NThunkF m v)
70-
buildThunk action = do
71-
freshThunkId <- freshId
72-
Thunk freshThunkId <$> newVar False <*> newVar (Deferred action)
73-
74-
-- 2021-02-25: NOTE: Please, look into thread handling of this.
75-
-- Locking system was not implemented at the time.
76-
-- How query operates? Is it normal that query on request if the thunk is locked - returns the thunk
77-
-- and when the value calculation is deferred - returns the thunk, it smells fishy.
78-
-- And because the query's impemetation are not used, only API - they pretty much could survive being that fishy.
79-
queryThunk
80-
:: (MonadVar m, MonadCatch m, Show (ThunkId m))
81-
=> m v
82-
-> NThunkF m v
83-
-> m v
84-
queryThunk = queryMF pure
85-
86-
forceThunk :: (MonadVar m, MonadCatch m, Show (ThunkId m))
87-
=> NThunkF m v
88-
-> m v
89-
forceThunk = forceF pure
90-
91-
forceEffects :: (MonadVar m, MonadCatch m, Show (ThunkId m))
92-
=> NThunkF m v
93-
-> m v
94-
forceEffects = forceEffF pure
95-
96-
furtherThunk :: (MonadVar m, MonadCatch m, Show (ThunkId m))
97-
=> NThunkF m v
98-
-> m (NThunkF m v)
99-
furtherThunk = furtherF id
115+
further t@(Thunk _ _ ref) = do
116+
_ <- atomicModifyVar ref $
117+
\x -> case x of
118+
Computed _ -> (x, x)
119+
Deferred d -> (Deferred d, x)
120+
pure t
100121

101122

102123
-- * Kleisli functor HOFs
103124

104-
instance (MonadVar m, MonadCatch m, Show (ThunkId m))
125+
instance (MonadBasicThunk m, MonadCatch m)
105126
=> MonadThunkF (NThunkF m v) m v where
106127

107128
queryMF
108-
:: ()
109-
=> (v -> m r)
129+
:: (v -> m r)
110130
-> m r
111131
-> NThunkF m v
112132
-> m r
113-
queryMF k n (Thunk _ active ref) = do
114-
thunkIsAvaliable <- not <$> atomicModifyVar active (True, )
115-
bool
116-
n
117-
go
118-
thunkIsAvaliable
119-
where
120-
go = do
121-
eres <- readVar ref
122-
res <-
123-
case eres of
124-
Computed v -> k v
125-
Deferred _mv -> n
126-
_ <- atomicModifyVar active (False, )
127-
pure res
133+
queryMF k n (Thunk _ active ref) =
134+
do
135+
thunkIsAvaliable <- not <$> atomicModifyVar active (True, )
136+
bool
137+
n
138+
go
139+
thunkIsAvaliable
140+
where
141+
go =
142+
do
143+
eres <- readVar ref
144+
res <-
145+
case eres of
146+
Computed v -> k v
147+
Deferred _mv -> n
148+
_ <- atomicModifyVar active (False, )
149+
pure res
128150

129151
forceF
130-
:: (MonadCatch m, Show (ThunkId m))
131-
=> (v -> m a)
152+
:: (v -> m a)
132153
-> NThunkF m v
133154
-> m a
134-
forceF k (Thunk n active ref) = do
135-
eres <- readVar ref
136-
case eres of
137-
Computed v -> k v
138-
Deferred action -> do
139-
nowActive <- atomicModifyVar active (True, )
140-
bool
141-
(do
142-
v <- catch action $ \(e :: SomeException) -> do
143-
_ <- atomicModifyVar active (False, )
144-
throwM e
145-
_ <- atomicModifyVar active (False, )
146-
writeVar ref (Computed v)
147-
k v
148-
)
149-
(throwM $ ThunkLoop $ show n)
150-
nowActive
155+
forceF k = k <=< force
151156

152157
forceEffF
153-
:: ()
154-
=> (v -> m r)
158+
:: (v -> m r)
155159
-> NThunkF m v
156160
-> m r
157-
forceEffF k (Thunk _ active ref) = do
158-
nowActive <- atomicModifyVar active (True, )
159-
bool
160-
(do
161-
eres <- readVar ref
162-
case eres of
163-
Computed v -> k v
164-
Deferred action -> do
165-
v <- action
166-
writeVar ref (Computed v)
167-
_ <- atomicModifyVar active (False, )
168-
k v
169-
)
170-
(pure $ error "Loop detected")
171-
nowActive
161+
forceEffF k = k <=< forceEff
172162

173163
furtherF
174-
:: ()
175-
=> (m v -> m v)
164+
:: (m v -> m v)
176165
-> NThunkF m v
177166
-> m (NThunkF m v)
178-
furtherF k t@(Thunk _ _ ref) = do
179-
_ <- atomicModifyVar ref $ \x -> case x of
180-
Computed _ -> (x, x)
181-
Deferred d -> (Deferred (k d), x)
182-
pure t
167+
furtherF k t@(Thunk _ _ ref) =
168+
do
169+
_ <- atomicModifyVar ref $
170+
\x -> case x of
171+
Computed _ -> (x, x)
172+
Deferred d -> (Deferred (k d), x)
173+
pure t
183174

src/Nix/Type/Infer.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ instance Monad m => MonadValueF (Judgment s) (InferT s m) where
436436
)
437437
-> Judgment s
438438
-> InferT s m (Judgment s)
439-
informF f j = f $ pure j
439+
informF f = f . pure
440440

441441
{-
442442
instance MonadInfer m

0 commit comments

Comments
 (0)