將串列推導式輸入 GHCi 不會生成串列,缺少最后的方括號,并且控制臺凍結。這就是我想出的:
[13*x 3 | x <- [1..], rem (13*x 3) 12 == 5, mod (13*x 3) 11 == 0, 13*x 3 <= 1000]
我相信問題出在x <- [1..], 或13*x 3 <= 1000. 我的意思是確定 x in可以采用的13*x 3 <= 1000值的上限。x <- [1..]
我得到了一個結果[341,但它確實缺少第二個方括號,并且控制臺凍結了。
uj5u.com熱心網友回復:
你的程式進入一個無限回圈。
第一個數字是 341,但為了生成下一個數字,您的程式會一直查看 的所有后續值x,評估這些值的所有守衛,并檢查所有守衛是否為真。最后的守衛,13*x 3 <= 1000永遠不會再變成真的,所以程式只是不斷地列舉x永遠的值。它正在尋找下一個x所有守衛都為真的此類,一旦找到,它就會列印它。但這樣x的永遠不會到來。
如果您希望串列結束一次x*13 3 > 1000,則必須使用takeWhile:
... | x <- takeWhile (\y -> y*13 3 <= 1000) [1..], ...
這樣,當串列達到 1000 時,串列實際上會停止x。不會產生更多的值。
uj5u.com熱心網友回復:
你給了編譯器太多的功勞。它不會仔細分析您的串列理解以推斷超過某個點將不再有結果,它應該呼叫串列完成。它只做你告訴它做的事情。
在這種情況下,您告訴它要做的是:
[ 13*x 3 -- produce numbers of the form 13*x 3
| x <- [1..] -- by searching all x from [1..]
, rem (13*x 3) 12 == 5 -- allowing only x that meet this condition
, mod (13*x 3) 11 == 0 -- and this condition
, 13*x 3 <= 1000 -- and this condition
]
因此它會列印[341并“凍結”,因為它仍在嘗試計算該串列的其余部分。x您看不到任何事情發生,但在內部,它從這些條件中汲取了更大的收益,[1..]并努力檢查了這些條件,以意識到不應包括該數字。但它永遠不會為了停止而結束,所以它永遠不會開始列印并等待更多輸入。[1..]]
使用您的代碼,您明確告訴編譯器您要搜索無限1串列中的每個數字[1..]。然后,您期望它注意到13*x 3 <= 1000只能x從有限前綴 of 中提取[1..],因此實際上不會[1..]按照您的指示搜索整個串列2。
這是一件完全合理的事情,我可以想象一個能夠實作這一目標的系統(至少在這樣的簡單條件下)。所以像這樣測驗它是否有效是個好主意!但是,除非有人真正告訴您,從串列推導中的條件中找出列舉上限是 GHC 可以提供的一項功能,否則當您告訴它搜索無限串列時,它永遠不會完成也就不足為奇了。
對于這種型別的串列理解(獲取滿足特定條件的范圍內的所有數字),您通常不應該使用[1..]然后嘗試強加停止條件。只需找出將傳遞13*x 3 <= 1000并[1..76]用作生成器的最后一個數字。您甚至可以讓 Haskell 使用[1 .. (1000 - 3) div為您解決問題 13]。
[1..]當您想要獲得正確形式的所有數字時,您可以使用生成器。然后,您可以使用類似take或的函式takeWhile在您想要將其用于某事的地方獲得一個有限的部分。例如
Prelude> let xs = [13*x 3 | x <- [1..], rem (13*x 3) 12 == 5, mod (13*x 3) 11 == 0]
Prelude> takeWhile (<= 1000) xs
[341]
Prelude> take 5 xs
[341,2057,3773,5489,7205]
事實上,用一個運算式表達你想要的最簡單和最直接的方法是:
takeWhile (<= 1000) [13*x 3 | x <- [1..], rem (13*x 3) 12 == 5, mod (13*x 3) 11 == 0]
串列推導中的所有內容(生成器運算式除外)一次只討論一個元素。無法表達將回傳串列作為一個整體討論的概念,例如“一旦回傳的數字超出此范圍就停止搜索”。但是這個概念在串列理解之外表達為普通函式( )是微不足道takeWhile (<= 1000)的。不要覺得你必須將整個計算硬塞到一個串列理解中。
1嚴格來說,如果您使用類似的型別Integer(這是 Haskell 將在沒有任何其他代碼使用結果對型別施加其他約束的情況下選擇的型別),那么它是無限的。如果您正在使用,Int那么它在技術上是有限的,并且您的串列理解最終將在它“用完數字”時結束。[1..]但是,對于詳盡的搜索,串列Int仍然不切實際。
但是,如果您使用較小的型別,例如Word16(needs to import from Data.Word),那么您實際上可以在實際時間內完成原始串列理解。(雖然我不得不稍微調整一下以確保這些13*x東西是以更大的型別計算的,所以它不會溢位)
Prelude> import Data.Word
Prelude Data.Word> [13*x 3 | x <- [1 :: Word16 ..], let x' = fromIntegral x, rem (13*x' 3) 12 == 5, mod (13*x' 3) 11 == 0, 13*x' 3 <= 1000]
[341]
2雖然我在腳注中很迂腐,但如果你的原始串列理解被評估為一個串列,Int那么在增長到足夠高而第一次失敗后停止甚至是無效的。嘗試這個:x13*x 3 <= 1000
Prelude Data.Word> let x = 768614336404564650 :: Int
Prelude Data.Word> 13*x 3 <= 1000
True
發生這種情況是因為實際上確實Int有一個上限,因此當您將其乘以 13 時,足夠大的值Int會溢位回負數。幾乎可以肯定,您的原始串列理解中有更多數字,如果是,它們只需要很長時間才能達到。[1..][Int]x = 77[Int]
再次演示的一個好方法是使用較小的有限型別,例如Word16. 如果我使用你的原始串列理解[Word16] 而不修改它以避免條件溢位,你會得到這個:
Prelude Data.Word> [13*x 3 | x <- [1..], rem (13*x 3) 12 == 5, mod (13*x 3) 11 == 0, 13*x 3 <= 1000] :: [Word16]
[341,605,209,869,473,77,737]
即使編譯器足夠聰明,可以知道[1..]可能通過13*x 3 <= 1000條件的區域,它也永遠無法讀懂您的想法并知道溢位產生的數字是您想要的解決方案還是代碼中的錯誤的結果. 它只是做你告訴它做的事情。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/528508.html
標籤:哈斯克尔ghci
上一篇:適用于Num和List的函式
下一篇:這個lambda函式有什么問題?
