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
108
109
|
module PFLP
( Probability
, Dist
, enum
, uniform
, certainly
, (>>>=)
, joinWith
, (??)
, RT
, pick
, replicateDist
) where
import Control.Search.Unsafe (allValues)
infixl 1 >>>=
infixr 1 ??
type Probability = Float
data Dist a = Dist { event :: a, prob :: Probability }
deriving Show
member :: [a] -> a
member = foldr (?) failed
enum :: [a] -> [Probability] -> Dist a
enum xs ps
| 1.0 - (foldl (+) 0.0 ps') < 1.0e-4 && all (> 0.0) ps'
= member (zipWith Dist xs ps')
| otherwise
= error ("PFLP.enum: probabilities do not add up to 1.0 " ++
"or are not strictly positive")
where ps' = take (length xs) ps
uniform :: [a] -> Dist a
uniform [] = error "PFLP.uniform: list of events must be non-empty"
uniform xs@(_:_) = enum xs (repeat (1.0 / fromInt (length xs)))
certainly :: a -> Dist a
certainly x = Dist x 1.0
(>>>=) :: Dist a -> (a -> Dist b) -> Dist b
d >>>= f = let Dist x p = d
Dist y q = f x
in Dist y (p * q)
joinWith :: (a -> b -> c) -> Dist a -> Dist b -> Dist c
joinWith f d1 d2 = do
x <- d1
y <- d2
return (f x y)
filterDist :: (a -> Bool) -> Dist a -> Dist a
filterDist p d | p (event d) = d
(??) :: (a -> Bool) -> Dist a -> Probability
(??) p = foldr (+) 0.0 . allValues . prob . filterDist p
type RT a = () -> a
pick :: RT a -> a
pick rt = rt ()
replicateDist :: Int -> RT (Dist a) -> Dist [a]
replicateDist n rt
| n == 0 = certainly []
| otherwise = joinWith (:) (pick rt) (replicateDist (n - 1) rt)
instance Functor Dist where
fmap f (Dist x p) = Dist (f x) p
instance Applicative Dist where
pure = certainly
(<*>) = joinWith ($)
instance Monad Dist where
return = certainly
(>>=) = (>>>=)
|