2012-07-26 71 views
1

tutorial繼續,在第一個更復雜的副作用:隨機數我來到這所:爲什麼隨機綁定的類型需要額外的StdGen?

bind :: (a → StdGen → (b,StdGen)) → (StdGen → (a,StdGen)) → (StdGen → (b,StdGen)) 

當「隨機函數」的類型(如作者所說的話)是如下:

a → StdGen -> (b,StdGen) 

此外,綁定定義爲:

bind f x seed = let (x',seed') = x seed in f x' seed' 

問題:爲什麼綁定有一個額外的StdGen它的簽名的結尾?它不應該是:

bind :: (a → StdGen → (b,StdGen)) → (StdGen → (a,StdGen)) → (b,StdGen) 

我的理由去如下:

  1. 綁定需要一個功能f:: a -> StdGen -> (b,StdGen)和 「輸出」 StdGen -> (a,StdGen)
  2. 它應用faStdGen,並返回任何的f簽名說它會 - 這就是(b, StdGen)

    f::a -> StdGen -> (b,StdGen) 
    
  3. 即使下面的綁定實現,f被應用到一個值x'seed'類型StdGen,所以它的結果必須是一個元組!

    bind f x seed = let (x',seed') = x seed in f x' seed' 
    

無論我去錯在那裏?任何幫助感謝!

注:對於未來的讀者,作者的bind定義等同於標準的人,除了與翻轉參數:flip . >>=

回答

3

讓我們把你的類型:

bind :: (a → StdGen → (b,StdGen)) → (StdGen → (a,StdGen)) → (b,StdGen) 

現在,我100%與你在第一點:

綁定功能f :: a -> StdGen -> (b,StdGen)和「輸出」StdGen -> (a,StdGen)

但是你的第二個讓我擔心:

它應用faStdGen

你從哪裏得到了類型爲a的值?你從哪裏得到StdGen的價值?

這兩個問題的答案是「你沒有一個謊言」;然而,由於你有一個StdGen -> (a,StdGen)說謊,你可以得到兩個,如果只有你有一個StdGen參數。這就是額外參數的來源。

現在,稍高級別的解釋。部分問題(我認爲)是這些類型的簽名有點太雜亂,無法舒適地閱讀。我們需要一些抽象。我們試圖在這裏建模的是概率分佈,我們將其作爲抽樣函數進行建模。因此,我們可以說在a分佈是知道如何從分佈採樣並返回a功能:

type Dist a = StdGen -> (a, StdGen) 

現在,並不是所有的分佈是如此平坦的一切。例如,伯努利分佈是「排序」,但它也參數化了選擇False的概率。我們可以這樣寫它的類型:

bernoulli :: Double -> Dist Bool 

因此,我們可以將參數化分佈建模爲返回分佈的函數;等價地,我們可以想到將分佈作爲參數化分佈返回的函數。

有了這個高層次的解釋

現在,bind類型變得更可讀:

bind :: (a -> Dist b) -> (Dist a -> Dist b) 

這就是說bind是從a分佈將告訴您如何第一個樣品的功能,然後用即a作爲從b分佈取樣時的參數。不僅如此,而且對於這種類型的別名,編寫bind的類型並不具有「額外」參數幾乎是不可想象的。

相關問題