forked from nsmryan/HEAL
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRandomly.hs
More file actions
107 lines (86 loc) · 2.36 KB
/
Randomly.hs
File metadata and controls
107 lines (86 loc) · 2.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
{-# LANGUAGE BangPatterns #-}
module Randomly (
test,
might,
mightM,
nextDouble,
nextInt,
nextBool,
selectFrom,
Randomizable(..),
pick,
choose,
chosen
) where
import EAMonad
import Linear as L
import System.Random.Mersenne.Pure64
import Control.Monad.Mersenne.Random
import Prelude as P
import Data.Sequence as S
import Data.Traversable as Tr
class Randomizable r where
generateFrom :: r -> EAMonad r e
instance Randomizable [a] where
generateFrom as = shuffle as
instance Randomizable (Seq a) where
generateFrom as = seqShuffle as
instance Randomizable Bool where
generateFrom b = nextBool
instance Randomizable Int where
generateFrom = nextInt
instance Randomizable Double where
generateFrom = nextDouble
nextDouble :: Double -> EAMonad Double e
nextDouble d = do
x <- randomly getDouble
return $! x*d
nextInt :: Int -> EAMonad Int e
nextInt d = do
x <- randomly getInt
return $! x `mod` d
nextBool :: EAMonad Bool e
nextBool = randomly getBool
test :: Double -> EAMonad Bool e
test p = do
x <- nextDouble 1
return $! p > x
might p f a = do
b <- test p
return $ if b then f a else a
mightM p f a = do
b <- test p
if b then f a else return $ a
selectFrom :: [a] -> EAMonad a e
selectFrom (a:as) = fairSelect 2.0 a as where
fairSelect _ a [] = return a
fairSelect n a (a':as) = do
b <- test (1.0/n)
let n' = n+1.0
if b then fairSelect n' a' as else fairSelect n' a as
shuffle :: [a] -> EAMonad [a] e
shuffle [] = return []
shuffle as = do
n <- nextInt $ P.length as
remaining <- shuffle $ dropNth as n
return $ (as !! n):remaining
dropNth :: [a] -> Int -> [a]
dropNth [] _ = []
dropNth (_:xs) 0 = xs
dropNth (x:xs) n = x:dropNth xs (n-1)
seqShuffle :: Seq a -> EAMonad (Seq a) e
seqShuffle s | S.null s = return S.empty
| otherwise = do
n <- nextInt $ S.length s
remaining <- seqShuffle $ dropNthSeq s n
return $ (s `S.index` n) <| remaining
dropNthSeq :: Seq a -> Int -> Seq a
dropNthSeq seq n = let (h, t) = S.splitAt n seq in h >< S.drop 1 t
pick :: (Linear l) => l a -> EAMonad a e
pick l = nextInt (count l) >>= return . L.index l
choose :: (Randomizable (l a), Linear l) => Int -> l a -> EAMonad (l a) e
choose n l = do
l' <- generateFrom l
return $ L.take n l'
chosen :: (Linear l) => l a -> EAMonad (l a) e
chosen l = Tr.mapM (const (pick l)) l