它是如何在这个" Prob"在learnyouahaskell教程中的monad?

时间:2015-11-12 23:34:20

标签: function haskell monads

我无法理解在以下实现中执行flipThree的返回:

import Data.Ratio  
import Data.List   
newtype Prob a = Prob { getProb :: [(a,Rational)] } deriving Show  


 -- Functor
instance Functor Prob where  
    fmap f (Prob xs) = Prob $ map (\(x,p) -> (f x,p)) xs  

-- Applicative
instance Applicative Prob where
  pure x = Prob [(x,1%1)]
  Prob [(x,r)] <*> something = fmap x something

-- Flatten works as join for Monads
flatten :: Prob (Prob a) -> Prob a  
flatten (Prob xs) = Prob $ concat $ map multAll xs  
    where multAll (Prob innerxs,p) = map (\(x,r) -> (x,p*r)) innerxs 

-- Monad
instance Monad Prob where  
    return x = Prob [(x,1%1)]  
    m >>= f = flatten (fmap f m)  
    fail _ = Prob []  

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)]  


flipThree :: Prob Bool
flipThree = do  
    a <- coin  
    b <- coin  
    c <- loadedCoin  
    return (all (==Tails) [a,b,c])

我可以跟随flipThree的实现,直到我到达以下行:

return (all (==Tails) [a,b,c])

根据我得到的结果,以下是:

Prob {getProb = [(False,1 % 40),(False,9 % 40),(False,1 % 40),(False,9 % 40),(False,1 % 40),(False,9 % 40),(False,1 % 40),(True,9 % 40)]}

我可以看到它来自之前:

Prob {getProb = [([Heads,Heads,Heads],1 % 40),([Heads,Heads,Tails],9 % 40),([Heads,Tails,Heads],1 % 40),([Heads,Tails,Tails],9 % 40),([Tails,Heads,Heads],1 % 40),([Tails,Heads,Tails],9 % 40),([Tails,Tails,Heads],1 % 40),([Tails,Tails,Tails],9 % 40)]}

只要我能看到列表monad的一些非确定性,但我不明白为什么。我的问题是理解为什么Coin的所有可能结果都在元组的第一个参数中连接起来,就像我们得到这个例子时那样:

[([Heads,Heads,Heads],1 % 40),([Heads,Heads,Tails],9 % 40)]

为什么monad列表以不同的方式定义Monad Prob并且返回时应该返回一个带有Rational 1%1的Prob?

注意:

教程的链接在这里:

http://learnyouahaskell.com/for-a-few-monads-more#making-monads

只要我整整一周都被理解了这一切,我真的很感激你能提供给我的任何帮助。

提前致谢。

1 个答案:

答案 0 :(得分:1)

Prob monad的工作原理与List monad类似,不同之处在于它还跟踪所有选择的当前概率。当你最终return某事时,这个当前概率乘以1%1来给出元组中的概率。

我们需要1%1,因为概率设置为术语的乘积,本产品的最终术语是1%1。

以下是这个monadic表达式发生的演练:

do a <- coin
   b <- coin
   return (a == b)
  1. 选择 a 的值和概率 - ( v1 p1 )。这会将 a 设置为 v1 以及当前概率公式 p1 * ...的公式。我们不知道是什么......直到达到monadic表达式结束时返回。
  2. 选择 b 的值和概率 - ( v2 p2 )。这将 b 设置为 v2 ,当前概率公式扩展为 p1 * p2 * ...
  3. 计算布尔值 a == b ,并通过将1替换为1来完成当前概率计算。生成的Prob元组将是(v1 == v2,p1 * p2 * 1)。