Skip to content

Commit ef82ae8

Browse files
authored
Merge pull request #223 from LSLeary/unique-symbol-generation
Unique Symbol Generation
2 parents da1a005 + b512313 commit ef82ae8

File tree

10 files changed

+146
-9
lines changed

10 files changed

+146
-9
lines changed

io-classes/CHANGELOG.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
# Revsion history of io-classes
22

3-
### next version
3+
## next release
44

55
### Breaking changes
66

77
### Non-breaking changes
88

99
* Improved performance of `tryReadTBQueueDefault`.
10+
* Added module `Control.Monad.Class.MonadUnique` generalising `Data.Unique`.
11+
* mtl: Added module `Control.Monad.Class.MonadUnique.Trans` providing monad transformer instances for `MonadUnique`.
1012

11-
### 1.8.0.1
13+
## 1.8.0.1
1214

1315
* Added support for `ghc-9.2`.
1416

@@ -33,13 +35,13 @@
3335
type classes.
3436
* Support ghc-9.12
3537

36-
### 1.7.0.0
38+
## 1.7.0.0
3739

3840
### Breaking changes
3941

4042
* Renamed `io-classes:io-classes-mtl` as `io-classes:mtl`.
4143

42-
### 1.6.0.0
44+
## 1.6.0.0
4345

4446
### Breaking changes
4547

io-classes/io-classes.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ library
8787
Control.Monad.Class.MonadTime
8888
Control.Monad.Class.MonadTimer
8989
Control.Monad.Class.MonadTest
90+
Control.Monad.Class.MonadUnique
9091
default-language: GHC2021
9192
default-extensions: LambdaCase
9293
build-depends: base >=4.16 && <4.22,
@@ -174,6 +175,7 @@ library mtl
174175
, Control.Monad.Class.MonadTime.SI.Trans
175176
, Control.Monad.Class.MonadTimer.Trans
176177
, Control.Monad.Class.MonadTimer.SI.Trans
178+
, Control.Monad.Class.MonadUnique.Trans
177179
build-depends: base,
178180
array,
179181
mtl,
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{-# OPTIONS_GHC -Wno-orphans #-}
2+
{-# LANGUAGE TypeFamilies #-}
3+
4+
module Control.Monad.Class.MonadUnique.Trans () where
5+
6+
import Control.Monad.Cont (ContT)
7+
import Control.Monad.Except (ExceptT)
8+
import Control.Monad.RWS.Lazy qualified as Lazy
9+
import Control.Monad.RWS.Strict qualified as Strict
10+
import Control.Monad.State.Lazy qualified as Lazy
11+
import Control.Monad.State.Strict qualified as Strict
12+
import Control.Monad.Writer.Lazy qualified as Lazy
13+
import Control.Monad.Writer.Strict qualified as Strict
14+
15+
import Control.Monad.Class.MonadUnique
16+
17+
18+
instance MonadUnique m => MonadUnique (ContT r m) where
19+
type Unique (ContT r m) = UniqueFor (ContT r) m
20+
21+
instance MonadUnique m => MonadUnique (ExceptT e m) where
22+
type Unique (ExceptT e m) = UniqueFor (ExceptT e) m
23+
24+
instance (MonadUnique m, Monoid w) => MonadUnique (Lazy.RWST r w s m) where
25+
type Unique (Lazy.RWST r w s m) = UniqueFor (Lazy.RWST r w s) m
26+
27+
instance (MonadUnique m, Monoid w) => MonadUnique (Strict.RWST r w s m) where
28+
type Unique (Strict.RWST r w s m) = UniqueFor (Strict.RWST r w s) m
29+
30+
instance MonadUnique m => MonadUnique (Lazy.StateT s m) where
31+
type Unique (Lazy.StateT s m) = UniqueFor (Lazy.StateT s) m
32+
33+
instance MonadUnique m => MonadUnique (Strict.StateT s m) where
34+
type Unique (Strict.StateT s m) = UniqueFor (Strict.StateT s) m
35+
36+
instance (MonadUnique m, Monoid w) => MonadUnique (Lazy.WriterT w m) where
37+
type Unique (Lazy.WriterT w m) = UniqueFor (Lazy.WriterT w) m
38+
39+
instance (MonadUnique m, Monoid w) => MonadUnique (Strict.WriterT w m) where
40+
type Unique (Strict.WriterT w m) = UniqueFor (Strict.WriterT w) m
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{-# LANGUAGE DefaultSignatures #-}
2+
{-# LANGUAGE TypeFamilyDependencies #-}
3+
4+
-- | A generalisation of the
5+
-- <https://hackage.haskell.org/package/base/docs/Data-Unique.html Data.Unique>
6+
-- API to both 'IO' and <https://hackage.haskell.org/package/io-sim IOSim>.
7+
--
8+
module Control.Monad.Class.MonadUnique
9+
( MonadUnique (..)
10+
, UniqueFor (..)
11+
) where
12+
13+
-- base
14+
import Data.Kind (Type)
15+
import Data.Unique qualified as IO
16+
17+
-- transformers
18+
import Control.Monad.Reader (MonadTrans (..), ReaderT (..), lift)
19+
20+
21+
class (Monad m, Eq (Unique m), Ord (Unique m)) => MonadUnique m where
22+
type Unique m = (unique :: Type) | unique -> m
23+
newUnique :: m (Unique m)
24+
hashUnique :: Unique m -> Int
25+
26+
default
27+
newUnique
28+
:: (m ~ t n, Unique m ~ UniqueFor t n, MonadTrans t, MonadUnique n)
29+
=> m (Unique m)
30+
default
31+
hashUnique
32+
:: (m ~ t n, Unique m ~ UniqueFor t n, MonadUnique n)
33+
=> Unique m -> Int
34+
newUnique = lift (MkUniqueFor <$> newUnique)
35+
hashUnique = hashUnique . unMkUniqueFor
36+
37+
instance MonadUnique IO where
38+
type Unique IO = IO.Unique
39+
newUnique = IO.newUnique
40+
hashUnique = IO.hashUnique
41+
42+
43+
newtype UniqueFor t m = MkUniqueFor{ unMkUniqueFor :: Unique m }
44+
deriving instance MonadUnique m => Eq (UniqueFor r m)
45+
deriving instance MonadUnique m => Ord (UniqueFor r m)
46+
47+
instance MonadUnique m => MonadUnique (ReaderT r m) where
48+
type Unique (ReaderT r m) = UniqueFor (ReaderT r) m

io-sim/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66

77
### Non-breaking changes
88

9+
* Added support for unique symbol generation à la `Data.Unique`.
910
* Removed a misleading internal comment.
1011

11-
### 1.8.0.1
12+
## 1.8.0.1
1213

1314
* Added support for `ghc-9.2`.
1415

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ module Control.Monad.IOSim
4848
, ThreadLabel
4949
, IOSimThreadId (..)
5050
, Labelled (..)
51+
, Unique
5152
-- ** Dynamic Tracing
5253
, traceM
5354
, traceSTM

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{-# LANGUAGE DeriveAnyClass #-}
22
{-# LANGUAGE DerivingStrategies #-}
33
{-# LANGUAGE DerivingVia #-}
4+
{-# LANGUAGE RoleAnnotations #-}
45

56
-- | Common types shared between `IOSim` and `IOSimPOR`.
67
--
@@ -28,6 +29,7 @@ module Control.Monad.IOSim.CommonTypes
2829
, BlockedReason (..)
2930
, Labelled (..)
3031
, ppLabelled
32+
, Unique (..)
3133
-- * Utils
3234
, ppList
3335
) where
@@ -202,6 +204,16 @@ ppLabelled :: (a -> String) -> Labelled a -> String
202204
ppLabelled pp Labelled { l_labelled = a, l_label = Nothing } = pp a
203205
ppLabelled pp Labelled { l_labelled = a, l_label = Just lbl } = concat ["Labelled ", pp a, " ", lbl]
204206

207+
-- | Abstract unique symbols à la "Data.Unique".
208+
newtype Unique s = MkUnique{ unMkUnique :: Integer }
209+
deriving stock (Eq, Ord)
210+
deriving newtype NFData
211+
type role Unique nominal
212+
213+
instance Hashable (Unique s) where
214+
hash = fromInteger . unMkUnique
215+
hashWithSalt = defaultHashWithSalt
216+
205217
--
206218
-- Utils
207219
--

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ data SimState s a = SimState {
143143
-- | list of clocks
144144
clocks :: !(Map ClockId UTCTime),
145145
nextVid :: !VarId, -- ^ next unused 'VarId'
146-
nextTmid :: !TimeoutId -- ^ next unused 'TimeoutId'
146+
nextTmid :: !TimeoutId, -- ^ next unused 'TimeoutId'
147+
nextUniq :: !(Unique s) -- ^ next unused @'Unique' s@
147148
}
148149

149150
initialState :: SimState s a
@@ -155,7 +156,8 @@ initialState =
155156
timers = PSQ.empty,
156157
clocks = Map.singleton (ClockId []) epoch1970,
157158
nextVid = 0,
158-
nextTmid = TimeoutId 0
159+
nextTmid = TimeoutId 0,
160+
nextUniq = MkUnique 0
159161
}
160162
where
161163
epoch1970 = UTCTime (fromGregorian 1970 1 1) 0
@@ -197,7 +199,7 @@ schedule !thread@Thread{
197199
threads,
198200
timers,
199201
clocks,
200-
nextVid, nextTmid,
202+
nextVid, nextTmid, nextUniq,
201203
curTime = time
202204
} =
203205
invariant (Just thread) simstate $
@@ -631,6 +633,13 @@ schedule !thread@Thread{
631633
thread' = thread { threadControl = ThreadControl k' ctl }
632634
schedule thread' simstate
633635

636+
NewUnique k -> do
637+
let thread' = thread{ threadControl = ThreadControl (k nextUniq) ctl }
638+
n = unMkUnique nextUniq
639+
simstate' = simstate{ nextUniq = MkUnique (n + 1) }
640+
SimTrace time tid tlbl (EventUniqueCreated n)
641+
<$> schedule thread' simstate'
642+
634643

635644
threadInterruptible :: Thread s a -> Bool
636645
threadInterruptible thread =

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ import Control.Monad.Class.MonadTime.SI qualified as SI
9393
import Control.Monad.Class.MonadTimer
9494
import Control.Monad.Class.MonadTimer.SI (TimeoutState (..))
9595
import Control.Monad.Class.MonadTimer.SI qualified as SI
96+
import Control.Monad.Class.MonadUnique
9697
import Control.Monad.Primitive qualified as Prim
9798
import Control.Monad.ST.Lazy
9899
import Control.Monad.ST.Strict qualified as StrictST
@@ -104,6 +105,7 @@ import Control.Monad.Fail qualified as Fail
104105
import Data.Bifoldable
105106
import Data.Bifunctor (bimap)
106107
import Data.Dynamic (Dynamic, toDyn)
108+
import Data.Hashable (Hashable (hash))
107109
import Data.List.Trace qualified as Trace
108110
import Data.Map.Strict (Map)
109111
import Data.Maybe (fromMaybe)
@@ -122,6 +124,7 @@ import GHC.Generics (Generic)
122124
import Quiet (Quiet (..))
123125

124126
import Control.Monad.IOSim.CommonTypes
127+
import Control.Monad.IOSim.CommonTypes qualified as Sim
125128
import Control.Monad.IOSim.STM
126129
import Control.Monad.IOSimPOR.Types
127130

@@ -193,6 +196,7 @@ data SimA s a where
193196
ExploreRaces :: SimA s b -> SimA s b
194197

195198
Fix :: (x -> IOSim s x) -> (x -> SimA s r) -> SimA s r
199+
NewUnique :: (Sim.Unique s -> SimA s r) -> SimA s r
196200

197201

198202
newtype STM s a = STM { unSTM :: forall r. (a -> StmA s r) -> StmA s r }
@@ -626,6 +630,11 @@ instance MonadTraceMVar (IOSim s) where
626630
instance MonadLabelledMVar (IOSim s) where
627631
labelMVar = labelMVarDefault
628632

633+
instance MonadUnique (IOSim s) where
634+
type Unique (IOSim s) = Sim.Unique s
635+
newUnique = IOSim (oneShot NewUnique)
636+
hashUnique = hash
637+
629638
data Async s a = Async !IOSimThreadId (STM s (Either SomeException a))
630639

631640
instance Eq (Async s a) where
@@ -1056,6 +1065,9 @@ data SimEventType
10561065
| EventThreadUnhandled SomeException
10571066
-- ^ thread terminated by an unhandled exception
10581067

1068+
| EventUniqueCreated Integer
1069+
-- ^ created the n-th 'Unique'
1070+
10591071
--
10601072
-- STM events
10611073
--
@@ -1163,6 +1175,7 @@ ppSimEventType = \case
11631175
EventThreadFinished -> "ThreadFinished"
11641176
EventThreadUnhandled a ->
11651177
"ThreadUnhandled " ++ show a
1178+
EventUniqueCreated n -> "UniqueCreated " ++ show n
11661179
EventTxCommitted written created mbEff ->
11671180
concat [ "TxCommitted ",
11681181
ppList (ppLabelled show) written, " ",

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ data SimState s a = SimState {
200200
nextTmid :: !TimeoutId, -- ^ next unused 'TimeoutId'
201201
-- | previous steps (which we may race with).
202202
-- Note this is *lazy*, so that we don't compute races we will not reverse.
203+
nextUniq :: !(Unique s), -- ^ next unused @'Unique' s@
203204
races :: Races,
204205
-- | control the schedule followed, and initial value
205206
control :: !ScheduleControl,
@@ -220,6 +221,7 @@ initialState =
220221
clocks = Map.singleton (ClockId []) epoch1970,
221222
nextVid = 0,
222223
nextTmid = TimeoutId 0,
224+
nextUniq = MkUnique 0,
223225
races = noRaces,
224226
control = ControlDefault,
225227
control0 = ControlDefault,
@@ -273,7 +275,7 @@ schedule thread@Thread{
273275
threads,
274276
timers,
275277
clocks,
276-
nextVid, nextTmid,
278+
nextVid, nextTmid, nextUniq,
277279
curTime = time,
278280
control,
279281
perStepTimeLimit
@@ -814,6 +816,13 @@ schedule thread@Thread{
814816
let thread' = thread { threadControl = ThreadControl k ctl }
815817
schedule thread' simstate
816818

819+
NewUnique k -> do
820+
let thread' = thread{ threadControl = ThreadControl (k nextUniq) ctl }
821+
n = unMkUnique nextUniq
822+
simstate' = simstate{ nextUniq = MkUnique (n + 1) }
823+
SimPORTrace time tid tstep tlbl (EventUniqueCreated n)
824+
<$> schedule thread' simstate'
825+
817826

818827
threadInterruptible :: Thread s a -> Bool
819828
threadInterruptible thread =

0 commit comments

Comments
 (0)