2016-04-19 55 views
0

我有上述功能,但是當我調用它時,它會卡住,Data.List.iterate的計算沒有停止。Data.List.iterate懶惰評估沒有發生

rp:: RandomGen g => g -> ([Int], g) 
rp g = (map (\x -> (last (fst x))) lst , snd (next g)) 
    where 
     lst = (Data.List.iterate id ([1], g_second)) 
     (g_first, g_second) = (split g) 

爲什麼會發生這種情況?

謝謝!

+2

什麼是'rp'應該做的?如果它應該創建一個隨機列表,則應該傳入隨機列表的期望長度... – Alec

+0

它假設首先結束。不是嗎? –

+0

元組中的第一個參數是無限列表'[1 ..]'因此我的問題是關於長度。 – Alec

回答

5

雖然我不完全確定你想用你的函數實現什麼,但它不停止的原因是因爲你正在映射一個無限列表並給它沒有理由 stop。

無限名單起源於你使用的iterate

lst = (Data.List.iterate id ([1], g_second))

你做了什麼有創建一個包含元組值([1], g_second)無限數量的無限列表。這似乎是一個邏輯錯誤 - 元組列表沒有變化;每個元素都是相同的,無窮大。需要明確的是,這個名單正在構建這個樣子的:

[([1], g_second), ([1], g_second), ([1], g_second), ([1], g_second)...] 

g_second是不變的,從來沒有得到一個理由來評價,所以在本質上,丟棄。

如果您要使用類似taketakeWhile的東西,可以強制該無限列表停止並返回已知數量的元素。然而,在這個語句中使用map

map (\x -> (last (fst x))) lst 

所有你做的是拉值1出來的元組的並永遠重複它。

而且因爲你放棄g_second而從不使用g_first,你的功能等同於以下內容:

rp :: RandomGen g => g -> ([Int], g) 
rp g = (repeat 1 , snd (next g)) 
2

假設你想基於一個RandomGen g隨機數的無限名單,那麼你可以使用Data.List.unfold因爲它適合的next很好:

> import System.Random 
> import Data.List 
> let rnds g = unfoldr (Just . next) g 
> let rnds' = rnds (mkStdGen 0) 
> take 3 rnds' 
[2147482884,2092764894,1390461064] 

BTW:最終g缺失 - 但要得到這個,你將不得不首先生成無限列表... ...這似乎不太可能(它不適合unfoldr很好;))