【问题标题】:How does it work the return in this "Prob" monad in the learnyouahaskell tutorial?在 learnyouahaskell 教程中的这个“Prob”monad 中的 return 是如何工作的?
【发布时间】:2015-11-13 08:34:30
【问题描述】:

我无法理解在以下实现中执行 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)]}

只要我能看到列表单子有一点不确定性,但我不明白为什么。我的问题是理解为什么 Coin 的所有可能结果都被连接到元组的第一个参数中,例如当我们得到这个时:

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

当 Monad Prob 以不同的方式定义并且返回应该返回一个具有 Rational 1 % 1 的 Prob 时,为什么 monad 列表会这样做?

注意:

教程链接在这里:

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

只要我整整一周都无法理解这一切,我将非常感谢您能为我提供的任何帮助。

提前致谢。

【问题讨论】:

  • return 确实返回一个概率为1%1 的值,但您看到的结果是coin &gt;&gt;= (\ a -&gt; coin &gt;&gt;= (\ b -&gt; loadedCoin &gt;&gt;= (\ c -&gt; return (all (== Tails) [a,b,c])))) 的结果。 return 的结果首先通过几层&gt;&gt;= 向上传递。这有帮助吗?
  • 不是返回最后一层 >>= 吗?
  • 这是&gt;&gt;=中嵌套最深的东西。它是 innermost 表达式。

标签: function haskell monads


【解决方案1】:

Prob monad 的工作方式与 List monad 类似,只是它还跟踪所有选择的当前概率。当你最终return某事时,这个当前概率乘以 1%1 得到元组中的概率。

我们需要最后的 1%1,因为概率被设置为项的乘积,而这个乘积的最终项是 1%1。

这里是这个单子表达式发生了什么的演练:

do a <- coin
   b <- coin
   return (a == b)
  1. a - (v1, p1) 选择一个值和概率。这会将 a 设置为 v1 以及当前概率公式 p1 * ... 的公式。在到达单子表达式末尾的 return 之前,我们不会知道 ... 是什么。
  2. b 选择一个值和概率 - (v2, p2)。这将 b 设置为 v2 并将当前概率公式扩展为 p1 * p2 * ...李>
  3. 计算布尔值 a == b,并通过将 ... 替换为 1%1 来完成当前概率计算。生成的 Prob 元组将是 (v1 == v2, p1 * p2 * 1)。

【讨论】:

  • 但是,如果在 Prob monad 的绑定运算符中,元组的第一个参数没有 concat 但它将函数 f 应用于第一个参数,那么返回如何连接所有可能性元组的参数。这是一个在第一个参数中连接所有“Heads”和“Tails”的函数?如果有,这个函数是从哪里来的?
  • 当表达式 [a, b, c] 被显式写入时会发生这种情况。这明确地创建了一个列表。
  • @user3457759 - return 并没有连接所有的可能性——它产生一种可能性。收集所有可能性就像 List monad 机器收集所有可能性一样,就像在do a &lt;- [1..3]; b &lt;- [4..5]; return (a+b) 中一样 - 所以如果你了解 List monad 是如何工作的,那么你就已经理解了 Prob monad 的工作原理了。
  • 我完全理解 list monad 是如何工作的,但我没有看到(在代码中)它是如何相似的(因为我不知道它在代码中的哪个位置是第一个元素的 concat元组)到 Prob Monad,其中绑定运算符完全与概率相乘相关,并且没有提及连接元组的第一个参数。
  • 没有真正的不确定性。在一张纸上研究[(Heads, 1 % 2), (Tails, 1 % 2)] &gt;&gt;= \ a -&gt; return (a == Tails) 的结果是如何工作的,从头到尾,只需代入定义即可。
猜你喜欢
  • 2018-08-04
  • 1970-01-01
  • 1970-01-01
  • 2018-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多