| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
List.Shuffle
Description
List shuffling and sampling with optimal asymptotic time and space complexity using the imperative Fisher–Yates algorithm.
Shuffling
shuffle_ :: RandomGen g => [a] -> g -> [a] Source #
\(\mathcal{O}(n)\). Like shuffle, but discards the final generator.
shuffleIO :: MonadIO m => [a] -> m [a] Source #
\(\mathcal{O}(n)\). Like shuffle, but uses the global random number generator.
Sampling
sample :: RandomGen g => Int -> [a] -> g -> ([a], g) Source #
\(\mathcal{O}(n)\). Sample elements of a list, without replacement.
sample_ c xs is equivalent to take c . shuffle_ xs, but with a constant factor that is proportional to c, not
the length of xs.
sample_ :: RandomGen g => Int -> [a] -> g -> [a] Source #
\(\mathcal{O}(n)\). Like sample, but discards the final generator.
sampleIO :: MonadIO m => Int -> [a] -> m [a] Source #
\(\mathcal{O}(n)\). Like sample, but uses the global random number generator.
Adapting to other monads
Reader monad
You are working in a reader monad, with access to a pseudo-random number generator somewhere in the environment,
in a mutable cell like an IORef or TVar:
import System.Random qualified as Random
import System.Random.Stateful qualified as Random
data MyMonad a
instance MonadIO MyMonad
instance MonadReader MyEnv MyMonad
data MyEnv = MyEnv
{ ...
, prng :: Random.AtomicGenM Random.StdGen
, ...
}In this case, you can adapt shuffle to work in your monad as follows:
import List.Shuffle qualified as List
import System.Random qualified as Random
shuffleList :: [a] -> MyMonad [a]
shuffleList list = do
MyEnv {prng} <- ask
Random.applyAtomicGen (List.shuffle list) prngState monad
You are working in a state monad with access to a pseudo-random number generator somewhere in the state type. You
also have a lens onto this field, which is commonly either provided by generic-lens/optics or written manually:
import System.Random qualified as Random
data MyState = MyState
{ ...
, prng :: Random.StdGen
, ...
}
prngLens :: Lens' MyState Random.StdGenIn this case, you can adapt shuffle to work in your monad as follows:
import Control.Lens qualified as Lens import Control.Monad.Trans.State.Strict qualified as State import List.Shuffle qualified as List shuffleList :: Monad m => [a] -> StateT MyState m [a] shuffleList = Lens.zoom prngLens . State.state . List.shuffle