Skip to content

Commit 734c9e3

Browse files
Merge branch 'main' into CAD-4738-stm-monad-catch-instance
2 parents d073a5b + 3dca67a commit 734c9e3

File tree

6 files changed

+98
-14
lines changed

6 files changed

+98
-14
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Change Log
22

3+
# Circa 2022.10.03 (pre release)
4+
5+
- Added `Semigroup` and `Monoid` instances for `STM` and `WrappedSTM` monads
6+
- Added `MArray` instance for `WrappedSTM` monad
7+
- Added `MonadFix` instance for `STM`
8+
39
# Circa 2022.09.27 (pre release)
410

511
- Module structure of `MonadSTM` changed to follow `stm` package structure.

io-classes/src/Control/Monad/Class/MonadSTM/Internal.hs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,18 @@ deriving instance MonadSTM m => Monad (WrappedSTM t r m)
13191319
deriving instance MonadSTM m => Alternative (WrappedSTM t r m)
13201320
deriving instance MonadSTM m => MonadPlus (WrappedSTM t r m)
13211321

1322+
instance ( Semigroup a, MonadSTM m ) => Semigroup (WrappedSTM t r m a) where
1323+
a <> b = (<>) <$> a <*> b
1324+
instance ( Monoid a, MonadSTM m ) => Monoid (WrappedSTM t r m a) where
1325+
mempty = pure mempty
1326+
1327+
instance ( MonadSTM m, MArray e a (STM m) ) => MArray e a (WrappedSTM t r m) where
1328+
getBounds = WrappedSTM . getBounds
1329+
getNumElements = WrappedSTM . getNumElements
1330+
unsafeRead arr = WrappedSTM . unsafeRead arr
1331+
unsafeWrite arr i = WrappedSTM . unsafeWrite arr i
1332+
1333+
13221334
-- note: this (and the following) instance requires 'UndecidableInstances'
13231335
-- extension because it violates 3rd Paterson condition, however `STM m` will
13241336
-- resolve to a concrete type of kind (Type -> Type), and thus no larger than

io-sim/src/Control/Monad/IOSim/Internal.hs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,19 @@ execAtomically !time !tid !tlbl !nextVid0 action0 k0 =
10311031
trace <- go ctl read written writtenSeq createdSeq nextVid k
10321032
return $ SimTrace time tid tlbl (EventLog x) trace
10331033

1034+
LiftSTStm st k ->
1035+
{-# SCC "schedule.LiftSTStm" #-} do
1036+
x <- strictToLazyST st
1037+
go ctl read written writtenSeq createdSeq nextVid (k x)
1038+
1039+
FixStm f k ->
1040+
{-# SCC "execAtomically.go.FixStm" #-} do
1041+
r <- newSTRef (throw NonTermination)
1042+
x <- unsafeInterleaveST $ readSTRef r
1043+
let k' = unSTM (f x) $ \x' ->
1044+
LiftSTStm (lazyToStrictST (writeSTRef r x')) (\() -> k x')
1045+
go ctl read written writtenSeq createdSeq nextVid k'
1046+
10341047
where
10351048
localInvariant =
10361049
Map.keysSet written

io-sim/src/Control/Monad/IOSim/Types.hs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ data SimA s a where
178178

179179
newtype STM s a = STM { unSTM :: forall r. (a -> StmA s r) -> StmA s r }
180180

181+
instance Semigroup a => Semigroup (STM s a) where
182+
a <> b = (<>) <$> a <*> b
183+
184+
instance Monoid a => Monoid (STM s a) where
185+
mempty = pure mempty
186+
181187
runSTM :: STM s a -> StmA s a
182188
runSTM (STM k) = k ReturnStm
183189

@@ -200,6 +206,9 @@ data StmA s a where
200206
-> (Maybe a -> a -> ST s TraceValue)
201207
-> StmA s b -> StmA s b
202208

209+
LiftSTStm :: StrictST.ST s a -> (a -> StmA s b) -> StmA s b
210+
FixStm :: (x -> STM s x) -> (x -> StmA s r) -> StmA s r
211+
203212
-- Exported type
204213
type STMSim = STM
205214

@@ -292,6 +301,9 @@ instance Alternative (STM s) where
292301

293302
instance MonadPlus (STM s) where
294303

304+
instance MonadFix (STM s) where
305+
mfix f = STM $ oneShot $ \k -> FixStm f k
306+
295307
instance MonadSay (IOSim s) where
296308
say msg = IOSim $ oneShot $ \k -> Say msg (k ())
297309

io-sim/src/Control/Monad/IOSimPOR/Internal.hs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,6 +1280,19 @@ execAtomically time tid tlbl nextVid0 action0 k0 =
12801280
-- TODO: step
12811281
return $ SimPORTrace time tid (-1) tlbl (EventLog x) trace
12821282

1283+
LiftSTStm st k ->
1284+
{-# SCC "schedule.LiftSTStm" #-} do
1285+
x <- strictToLazyST st
1286+
go ctl read written writtenSeq createdSeq nextVid (k x)
1287+
1288+
FixStm f k ->
1289+
{-# SCC "execAtomically.go.FixStm" #-} do
1290+
r <- newSTRef (throw NonTermination)
1291+
x <- unsafeInterleaveST $ readSTRef r
1292+
let k' = unSTM (f x) $ \x' ->
1293+
LiftSTStm (lazyToStrictST (writeSTRef r x')) (\() -> k x')
1294+
go ctl read written writtenSeq createdSeq nextVid k'
1295+
12831296
where
12841297
localInvariant =
12851298
Map.keysSet written

io-sim/test/Test/IOSim.hs

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,18 @@ tests =
139139
[ testProperty "Reference vs IO" prop_stm_referenceIO
140140
, testProperty "Reference vs Sim" prop_stm_referenceSim
141141
]
142-
, testGroup "MonadFix instance"
143-
[ testProperty "purity" prop_mfix_purity
144-
, testProperty "purity2" prop_mfix_purity_2
145-
, testProperty "tightening" prop_mfix_left_shrinking
146-
, testProperty "lazy" prop_mfix_lazy
147-
, testProperty "recdata" prop_mfix_recdata
142+
, testGroup "MonadFix instances"
143+
[ testGroup "IOSim"
144+
[ testProperty "purity" prop_mfix_purity_IOSim
145+
, testProperty "purity2" prop_mfix_purity_2
146+
, testProperty "tightening" prop_mfix_left_shrinking_IOSim
147+
, testProperty "lazy" prop_mfix_lazy
148+
, testProperty "recdata" prop_mfix_recdata
149+
]
150+
, testGroup "STM"
151+
[ testProperty "purity" prop_mfix_purity_STM
152+
, testProperty "tightening" prop_mfix_left_shrinking_STM
153+
]
148154
]
149155
-- NOTE: Most of the tests below only work because the io-sim
150156
-- scheduler works the way it does.
@@ -592,15 +598,18 @@ test_wakeup_order = do
592598

593599
-- | Purity demands that @mfix (return . f) = return (fix f)@.
594600
--
595-
prop_mfix_purity :: Positive Int -> Bool
596-
prop_mfix_purity (Positive n) =
597-
runSimOrThrow
598-
(mfix (return . factorial)) n
599-
== fix factorial n
601+
prop_mfix_purity_m :: forall m. MonadFix m => Positive Int -> m Bool
602+
prop_mfix_purity_m (Positive n) =
603+
(== fix factorial n) . ($ n) <$> mfix (return . factorial)
600604
where
601605
factorial :: (Int -> Int) -> Int -> Int
602606
factorial = \rec_ k -> if k <= 1 then 1 else k * rec_ (k - 1)
603607

608+
prop_mfix_purity_IOSim :: Positive Int -> Bool
609+
prop_mfix_purity_IOSim a = runSimOrThrow $ prop_mfix_purity_m a
610+
611+
prop_mfix_purity_STM:: Positive Int -> Bool
612+
prop_mfix_purity_STM a = runSimOrThrow $ atomically $ prop_mfix_purity_m a
604613

605614
prop_mfix_purity_2 :: [Positive Int] -> Bool
606615
prop_mfix_purity_2 as =
@@ -634,12 +643,12 @@ prop_mfix_purity_2 as =
634643
(realToFrac `map` as')
635644

636645

637-
prop_mfix_left_shrinking
646+
prop_mfix_left_shrinking_IOSim
638647
:: Int
639648
-> NonNegative Int
640649
-> Positive Int
641650
-> Bool
642-
prop_mfix_left_shrinking n (NonNegative d) (Positive i) =
651+
prop_mfix_left_shrinking_IOSim n (NonNegative d) (Positive i) =
643652
let mn :: IOSim s Int
644653
mn = do say ""
645654
threadDelay (realToFrac d)
@@ -657,6 +666,25 @@ prop_mfix_left_shrinking n (NonNegative d) (Positive i) =
657666
threadDelay (realToFrac d) $> a : rec_)))
658667

659668

669+
prop_mfix_left_shrinking_STM
670+
:: Int
671+
-> Positive Int
672+
-> Bool
673+
prop_mfix_left_shrinking_STM n (Positive i) =
674+
let mn :: STMSim s Int
675+
mn = do say ""
676+
return n
677+
in
678+
take i
679+
(runSimOrThrow $ atomically $
680+
mfix (\rec_ -> mn >>= \a -> return $ a : rec_))
681+
==
682+
take i
683+
(runSimOrThrow $ atomically $
684+
mn >>= \a ->
685+
(mfix (\rec_ -> return $ a : rec_)))
686+
687+
660688

661689
-- | 'Example 8.2.1' in 'Value Recursion in Monadic Computations'
662690
-- <https://leventerkok.github.io/papers/erkok-thesis.pdf>
@@ -756,7 +784,7 @@ probeOutput probe x = atomically (modifyTVar probe (x:))
756784

757785

758786
--
759-
-- Syncronous exceptions
787+
-- Synchronous exceptions
760788
--
761789

762790
unit_catch_0, unit_catch_1, unit_catch_2, unit_catch_3, unit_catch_4,

0 commit comments

Comments
 (0)