> return x = Prob [(x,1 % 1)]
> m >>= f = flatten (fmap f m)
> fail _ = Prob []
Поскольку мы уже сделали всю тяжелую работу, экземпляр очень прост. Мы определили функцию >fail
, которая такова же, как и для списков, поэтому если при сопоставлении с образцом в выражении >do
происходит неудача, неудача случается в контексте списка вероятностей.
Важно также проверить, что для только что созданной нами монады выполняются законы монад:
1. Первое правило говорит, что выражение >return x >>= f
должно равняться выражению >f x
. Точное доказательство было бы довольно громоздким, но нам видно, что если мы поместим значение в контекст по умолчанию с помощью функции >return
, затем отобразим это с помощью функции, используя >fmap
, а потом отобразим результирующий список вероятностей, то каждая вероятность, являющаяся результатом функции, была бы умножена на вероятность >1 % 1
, которую мы создали с помощью функции >return
, так что это не повлияло бы на контекст.
2. Второе правило утверждает, что выражение >m >> return
ничем не отличается от >m
. Для нашего примера доказательство того, что выражение >m >> return
равно просто >m
, аналогично доказательству первого закона.
3. Третий закон утверждает, что выражение >f <=< (g <=< h)
должно быть аналогично выражению >(f <=< g) <=< h
. Это тоже верно, потому что данное правило выполняется для списковой монады, которая составляет основу для монады вероятностей, и потому что умножение ассоциативно. >1 % 2 * (1 % 3 * 1 % 5)
равно >(1 % 2 * 1 % 3) * 1 % 5
.
Теперь, когда у нас есть монада, что мы можем с ней делать? Она может помочь нам выполнять вычисления с вероятностями. Мы можем обрабатывать вероятностные события как значения с контекстами, а монада вероятностей обеспечит отражение этих вероятностей в вероятностях окончательного результата.
Скажем, у нас есть две обычные монеты и одна монета, с одной стороны налитая свинцом: она поразительным образом выпадает на решку девять раз из десяти и на орла – лишь один раз из десяти. Если мы подбросим все монеты одновременно, какова вероятность того, что все они выпадут на решку? Во-первых, давайте создадим значения вероятностей для подбрасывания обычной монеты и для монеты, налитой свинцом:
>data Coin = Heads | Tails deriving (Show, Eq)
>coin :: Prob Coin
>coin = Prob [(Heads,1 % 2),(Tails,1 % 2)]
>loadedCoin :: Prob Coin
>loadedCoin = Prob [(Heads,1 % 10),(Tails,9 % 10)]
И наконец, действие по подбрасыванию монет:
>import Data.List (all)
>flipThree :: Prob Bool
>flipThree = do
> a <– coin
> b <– coin
> c <– loadedCoin
> return (all (==Tails) [a,b,c])