2016-05-12 32 views
3

我有一個幾乎純粹的數學計算程序。問題是這些計算中的一部分是在蒙特卡羅生成的值上運行的。如何在隨機值計算的哈斯克爾程序中構造monads?

好像我有兩個設計方案:

要麼我所有的計算功能,採取包含預先生成的蒙特卡洛鏈附加參數。這讓我可以在任何地方保持純粹的功能,但是由於存在調用其他函數的函數,因此會在代碼庫中添加很多線路噪聲。

另一種選擇是使所有的計算功能單點。這似乎是不幸的,因爲一些函數甚至沒有使用那些隨機值,他們只是調用一個函數來調用一個需要隨機值的函數。

這裏有關於首選設計的指導嗎?具體而言,蒙特卡洛值所關心的代碼中的monadic/non-monadic函數的分離?

+1

您是否在每一步需要轉發到下一個函數時創建新的值,還是隻使用多個函數中的單個值?如果前者那麼國家monad會是一個不錯的選擇,如果後者那麼讀者monad可能是你最好的選擇。實際上你可以使用'MonadReader'編寫你的函數,然後如果你願意的話可以在以後用它們作爲純函數。 – bheklilr

+0

這是否類似於傳遞預計算上下文,除非天真地傳遞一個列表,列表將被讀者或狀態取代? – daj

+0

爲所有函數添加一個參數,或者將它們全部轉換爲一元操作,並不是唯一的選擇,因爲某些函數甚至不使用隨機值。不要改變那些不需要隨機性/非確定性的fns - 讓它們保持純淨。你總是可以通過你的單子/函數對它們進行「fmap」,或者在monad中的let表達式中使用它們。對於需要隨機性的動作,你可以讓他們生活在一個有MonadReader StdGen m'約束的monad中,或者讓這些fns保持純淨,但給他們一個'StdGen'參數,'拆分舊的生成器以獲得新的生成器。 。 – liminalisht

回答

2

另一種選擇是使所有的計算功能單點。這似乎是不幸的,因爲一些函數甚至沒有使用那些隨機值,他們只是調用一個函數來調用一個需要隨機值的函數。

我會建議遵循這種方法,我不同意你的評估它是「不幸的」。什麼單子擅長恰恰將您的純代碼從您的副作用分離出來。您的純函數可以具有純粹的類型,並且方法可以用隨機生成部分「掛鉤」。默想標準操作(這裏專門到一些理想化的Random單子型)的簽名:

-- Apply a pure function to a randomly selected value. 
fmap :: (a -> b) -> Random a -> Random b 

-- Apply a randomly selected function to a randomly selected argument. 
-- The two random choices are independent. 
(<*>) :: Random (a -> b) -> Random a -> Random b 

-- Apply a two-argument function to a randomly selected arguments. 
-- The two random choices are independent. 
liftA2 :: (a -> b -> c) -> Random a -> Random b -> Random c 

-- Make a `Random b` choice whose distribution depends on the value 
-- sampled from the `Random a`. 
(>>=) :: Random a -> (a -> Random b) -> Random b 

所以你的方法的改寫版本是:

  • 寫純無論你能功能。
  • 通過使用Functor/Applicative/Monad類操作來調整這些純函數以處理隨機值。
  • 無論您發現一個多餘提及Random類型的函數,都要弄清楚如何使用這些類的操作(或其存在的豐富的效用函數)將Random分解出來。

這是不特定的隨機數生成,順便說一下,但適用於任何單子

你可能會喜歡閱讀這篇文章,可能想看看筆者的隨機生成單子庫:

我懷疑你需要按照本文的方法使用免費monads進行建模,但關於概率分佈monad的概念位可能會有所幫助。

+0

感謝您的指針。我一直故意避免免費單子,因爲我想先內化香草單子。賈裏德似乎在做一些很酷的事情,我希望有更多的人在哈斯克爾社區做數字/科學計算。 「不幸的是」只是指一個初學者的觀點,它可以更容易地找到非一元代碼。我知道更多的練習,我會通過更深入的練習來欣賞紀律的好處,但需要一些習慣。 – daj

+0

@daj:我會再次強調,我懷疑你需要鑽研自由單體以從本文中受益。你的「一次一件」態度是正確的,只是首先關注如何有效地使用RNG monad庫。 –

0

tl; dr: 考慮抽象隨機函數發生器並將其作爲參數傳遞。 Haskells類型類應該可以幫助您儘可能隱藏該抽象。

不幸的是,這裏沒有銀彈。由於您使用的是副作用,因此您的「功能」根本不是正確意義上的功能。 Haskell不允許你隱藏這個事實(它構成了它的安全保證的最大部分)。所以在某些方面你需要表達這個事實。您似乎也混淆了單調操作和(普通)函數之間的差異:(間接)使用隨機值的函數是隱式單調的。一次性操作中可以始終使用非一元函數。所以你可能應該實現所有真正的非一元函數,看看它有多遠。作爲一個完全無關的方面說明:如果懶惰不是必需條件,Haskells強大的安全性對你來說太過重擔,但你仍然希望寫(大部分)功能性代碼,你可以試試OCaml(或者任何其他ML方言)。