{-| Module  : FiniteCategories
Description : Sample randomly a list.
Copyright   : Guillaume Sabbagh 2021
License     : GPL-3
Maintainer  : guillaumesabbagh@protonmail.com
Stability   : experimental
Portability : portable

Sample randomly a list.
-}

module Utils.Sample 
(
    pickOne,
    sample
)
where
    import System.Random                            (RandomGen, uniformR)
    
    -- | Pick one element of a list randomly.

    pickOne :: (RandomGen g) => [a] -> g -> (a,g)
    pickOne :: forall g a. RandomGen g => [a] -> g -> (a, g)
pickOne [] g
g = [Char] -> (a, g)
forall a. HasCallStack => [Char] -> a
error [Char]
"pickOne in an empty list."
    pickOne [a]
l g
g = (([a]
l [a] -> Int -> a
forall a. [a] -> Int -> a
!! Int
index),g
newGen) where
        (Int
index,g
newGen) = ((Int, Int) -> g -> (Int, g)
forall g a. (RandomGen g, UniformRange a) => (a, a) -> g -> (a, g)
uniformR (Int
0,([a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
l)Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) g
g)
        
    listWithoutNthElem :: [a] -> Int -> [a]
    listWithoutNthElem :: forall a. [a] -> Int -> [a]
listWithoutNthElem [] Int
_ = []
    listWithoutNthElem (a
x:[a]
xs) Int
0 = [a]
xs
    listWithoutNthElem (a
x:[a]
xs) Int
k = a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:([a] -> Int -> [a]
forall a. [a] -> Int -> [a]
listWithoutNthElem [a]
xs (Int
kInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1))
        
    -- | Sample /n/ elements of a list randomly.

    sample :: (RandomGen g) => [a] -> Int -> g -> ([a],g)
    sample :: forall g a. RandomGen g => [a] -> Int -> g -> ([a], g)
sample [a]
_ Int
0 g
g = ([],g
g)
    sample [] Int
k g
g = [Char] -> ([a], g)
forall a. HasCallStack => [Char] -> a
error [Char]
"Sample size bigger than the list size."
    sample [a]
l Int
n g
g = (([a]
l [a] -> Int -> a
forall a. [a] -> Int -> a
!! Int
index)a -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
rest,g
finalGen) where
        (Int
index,g
newGen) = ((Int, Int) -> g -> (Int, g)
forall g a. (RandomGen g, UniformRange a) => (a, a) -> g -> (a, g)
uniformR (Int
0,([a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
l)Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) g
g)
        new_l :: [a]
new_l = [a] -> Int -> [a]
forall a. [a] -> Int -> [a]
listWithoutNthElem [a]
l Int
index
        ([a]
rest,g
finalGen) = [a] -> Int -> g -> ([a], g)
forall g a. RandomGen g => [a] -> Int -> g -> ([a], g)
sample [a]
new_l (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) g
newGen