Skip to content

Commit 7532837

Browse files
authored
Merge pull request #161 from haskell/lehins/avoid-too-strict-mutation
Make result lazy when mutating
2 parents 90d92a8 + 5db2353 commit 7532837

File tree

1 file changed

+25
-4
lines changed

1 file changed

+25
-4
lines changed

src/System/Random/Stateful.hs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{-# LANGUAGE BangPatterns #-}
2+
{-# LANGUAGE CPP #-}
23
{-# LANGUAGE FlexibleInstances #-}
34
{-# LANGUAGE FunctionalDependencies #-}
45
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
@@ -143,6 +144,10 @@ import Data.STRef
143144
import Foreign.Storable
144145
import System.Random
145146
import System.Random.Internal
147+
#if __GLASGOW_HASKELL__ >= 808
148+
import GHC.IORef (atomicModifyIORef2Lazy)
149+
#endif
150+
146151

147152
-- $introduction
148153
--
@@ -414,7 +419,7 @@ instance (RandomGen g, MonadIO m) => FrozenGen (AtomicGen g) m where
414419
type MutableGen (AtomicGen g) m = AtomicGenM g
415420
freezeGen = fmap AtomicGen . liftIO . readIORef . unAtomicGenM
416421
modifyGen (AtomicGenM ioRef) f =
417-
liftIO $ atomicModifyIORef' ioRef $ \g ->
422+
liftIO $ atomicModifyIORefHS ioRef $ \g ->
418423
case f (AtomicGen g) of
419424
(a, AtomicGen g') -> (g', a)
420425
{-# INLINE modifyGen #-}
@@ -436,11 +441,27 @@ instance (RandomGen g, MonadIO m) => ThawedGen (AtomicGen g) m where
436441
-- @since 1.2.0
437442
applyAtomicGen :: MonadIO m => (g -> (a, g)) -> AtomicGenM g -> m a
438443
applyAtomicGen op (AtomicGenM gVar) =
439-
liftIO $ atomicModifyIORef' gVar $ \g ->
444+
liftIO $ atomicModifyIORefHS gVar $ \g ->
440445
case op g of
441446
(a, g') -> (g', a)
442447
{-# INLINE applyAtomicGen #-}
443448

449+
-- HalfStrict version of atomicModifyIORef, i.e. strict in the modifcation of the contents
450+
-- of the IORef, but not in the result produced.
451+
atomicModifyIORefHS :: IORef a -> (a -> (a, b)) -> IO b
452+
atomicModifyIORefHS ref f = do
453+
#if __GLASGOW_HASKELL__ >= 808
454+
(_old, (_new, res)) <- atomicModifyIORef2Lazy ref $ \old ->
455+
case f old of
456+
r@(!_new, _res) -> r
457+
pure res
458+
#else
459+
atomicModifyIORef ref $ \old ->
460+
case f old of
461+
r@(!_new, _res) -> r
462+
#endif
463+
{-# INLINE atomicModifyIORefHS #-}
464+
444465
-- | Wraps an 'IORef' that holds a pure pseudo-random number generator.
445466
--
446467
-- * 'IOGenM' is safe in the presence of exceptions, but not concurrency.
@@ -526,7 +547,7 @@ applyIOGen :: MonadIO m => (g -> (a, g)) -> IOGenM g -> m a
526547
applyIOGen f (IOGenM ref) = liftIO $ do
527548
g <- readIORef ref
528549
case f g of
529-
(!a, !g') -> a <$ writeIORef ref g'
550+
(a, !g') -> a <$ writeIORef ref g'
530551
{-# INLINE applyIOGen #-}
531552

532553
-- | Wraps an 'STRef' that holds a pure pseudo-random number generator.
@@ -600,7 +621,7 @@ applySTGen :: (g -> (a, g)) -> STGenM g s -> ST s a
600621
applySTGen f (STGenM ref) = do
601622
g <- readSTRef ref
602623
case f g of
603-
(!a, !g') -> a <$ writeSTRef ref g'
624+
(a, !g') -> a <$ writeSTRef ref g'
604625
{-# INLINE applySTGen #-}
605626

606627
-- | Runs a monadic generating action in the `ST` monad using a pure

0 commit comments

Comments
 (0)