2014-07-24 130 views
6

我想通過使用Control.Monad.Random庫來評估Haskell中的隨機計算。下面的作品就好了:Haskell - 在蘭德monad中計時計算

ghci> import System.Timeout 
ghci> import Control.Monad.Random 
ghci> timeout 1000 . evalRandIO $ getRandomR (True, False) 
Just True 

然而,這種方法似乎並不工作,如果我們有Rand StdGen a類型永遠不會終止的(即計算結果爲底部)計算。例如:

ghci> let f = f :: Rand StdGen Bool 
ghci> timeout 1000 $ evalRandIO f 
Just 

這裏GHCI打印「公正」,然後無限期掛起試圖評估f。那些對Haskell運行時知道更多的人可以解釋爲什麼會發生這種情況,以及如何解決它?我的猜測是表達式evalRandIO f被評估爲WHNF,所以timeout 10認爲計算將終止,但我真的不知道。

回答

5

如果你做類似

> Just x <- timeout 1000 $ evalRandIO f 
> :t x 
x :: Bool 
> x 
Interrupted. 

計算本身完成,即它達到WHNF這可能更有意義,所以timeout不抓住它。 timeout 1000函數本身完成並返回Just undefined。一個例子,你可以得到timeout趕底的評價是

> import Control.DeepSeq 
> :set +m -- Multiline mode 
> let f :: Bool 
|  f = f 
| 
> timeout 1000000 $ deepseq f (return f) 
Nothing 

你會看到它掛起一秒鐘,然後返回Nothingdeepseq沒有完成評估f所以它可以執行return f

所以是的,你的問題源於f = f被評估爲WHNF而不是NF的事實。爲了強制NF,你需要使用類似deepseq的東西。另一個可能更簡單的例子是隻使用$!運營商,如:

> let f :: Rand StdGen Bool 
|  f = f 
| 
> timeout 1000000 $ evalRandIO $! f 
Nothing 
+0

謝謝!我清楚地知道seq/deepseq和Haskell運行時間。 – user3873438

+0

@ user3873438公平起見,我不得不加載GHCi會話來自己弄清楚。懶惰引起一些有趣的問題,但大多數時候你甚至不需要考慮它。大多數情況下,當你遇到需要事情按特定順序發生的問題時,你需要開始擔心嚴格性,在這種情況下,你希望''evalRandIO f'在'timeout 1000'結束之前發生。有了這樣的關係,重要的是要嚴格要求嚴格,這就是'deepseq'和'$!'所做的。 – bheklilr

+0

您還需要擔心空間泄漏和並行性的懶惰。 – PyRulez