簡體   English   中英

Haskell(GHCi)的范圍

[英]Ranges in Haskell (GHCi)

我正在讀“ 為了好大學而學習你的哈斯克爾” 他的例子 [2,2..20][3, 6..20]工作正常,但我得到了三個奇怪的結果:

  1. 從17到17計數17: [17, 1..171]得到空列表。
  2. 從17到1711111計數17: [17, 17..171111]重復數字17直到我中斷GHCi。
  3. take 54 [171, 234..]take 54 [171, 244..] take 54 [171, 234..]之間有一個奇怪的區別:

      ghci> take 54 [171, 234..] [171,234,297,360,423,486,549,612,675,738,801,864,927,990,1053,1116,1179,1242,1305,1368,1431,1494,1557,1620,1683,1746,1809,1872,1935,1998,2061,2124,2187,2250,2313,2376,2439,2502,2565,2628,2691,2754,2817,2880,2943,3006,3069,3132,3195,3258,3321,3384,3447,3510] ghci> take 54 [171, 244..] [171,244,317,390,463,536,609,682,755,828,901,974,1047,1120,1193,1266,1339,1412,1485,1558,1631,1704,1777,1850,1923,1996,2069,2142,2215,2288,2361,2434,2507,2580,2653,2726,2799,2872,2945,3018,3091,3164,3237,3310,3383,3456,3529,3602,3675,3748,3821,3894,3967,4040] 

為什么?

你有略微偏離范圍的含義。 Haskell范圍語法是四個方面之一: [first..][first,second..][first..last][first,second..last] 來自Learn You A Haskell的例子是

ghci> [2,4..20]  
[2,4,6,8,10,12,14,16,18,20]  
ghci> [3,6..20]  
[3,6,9,12,15,18]   

請注意,在第一種情況下,列表按兩次計數,而在第二種情況下,列表按三次計算。 那是因為第一和第二項之間的差異分別是兩個和三個。 在你的語法中,你正在嘗試編寫[first,step..last]來獲取列表[first,first+step,first+2*step,...,last] ; 但是,這樣的范圍的步長實際上是前兩個數字之間的差異。 沒有第二個元素,步長總是一個; 如果沒有最終元素,列表將永遠持續(或直到達到類型的最大/最小元素)。

因此,讓我們看看你的三個例子:

  • [17,1..171] == [] 由於你指定17,1 ,Haskell看到列表的前兩個元素應該是17和1,所以你必須按-16計數。 在這種情況下,Haskell想要在元素小於最后一個元素時立即停止---但它們以這種方式開始,因此不會產生任何元素。 要按1計算,你需要[17,18..171] (列表的前兩個元素是17和18),或者只是[17..171]

  • [17, 17..171111] == repeat 17 這個很有趣。 由於列表中的前兩個元素都是17 ,因此Haskell確定您必須按零計數 - 並且它將很樂意繼續計數,直到結果超過171111 當然,當計數為零時,這將永遠不會發生,因此您將得到七個無限的列表。 如果你認為更清楚,你需要[17,34..171111][17,17+17..171111]

  • take 54 [171,234..] 對陣 take 54 [171,244..] 我不確定你在這里期待什么行為,但是他們每個人都在做什么與上面相同:第一個返回一個54個整數的列表,從171開始,計數234 - 171 = 63 ; 第二個返回一個54個整數的列表,從171開始,按244 - 171 = 73計數。 每個列表都無限遠(或者至少直到maxBound ,如果列表是有限的Ints而不是任意大的Integers ),所以你只需要前五十四個元素。

關於范圍語法意味着什么范圍(它被翻譯成Enum類型類中的函數)的一些更細微的細節,包括對浮點數范圍的略微驚人的行為, hammar對另一個問題有一個很好的答案

那么,這些操作的語義與你期望的有點不同。 構造[a,b..c]實際上只是enumFromThenTo abc語法糖,其行為有點像這樣:

計算d = b - a [a,b..c]的輸出是[a,a+d,a+d+d,a+d+d+d,...] 這是重復的,直到a+n*d > c ,如果dc - a有不同的符號(在這種情況下,列表將是無限的,所以沒有輸出),或者直到達到maxBoundminBound ,然后輸出結束。 (當然,這是以不同的方式實現的,因為我們在這里使用了Enum任意實例)。

所以[1,3..10]變為[1,3,5,7,9]並且自[17, 17..171111] 17 - 17 = 0[17, 17..171111]得到[17,17+0,17+0+0...] 通過這個稍微復雜的規則, [17, 1..171]產生空列表。

另外: [x,y..]是使用函數enumFromThen xy ,其行為與enumFromThenTo類似,只是沒有邊界條件,所以如果你的Enum是無限的,那么結果列表也是如此。

我也對這種行為感到有些驚訝,所以我寫了一個對我來說感覺更自然的范圍函數(也許對你來說也是如此):

range step start end = takeWhile (<=end) $ iterate (+step) start

引用你的例子:

按17分從1到171計算

range 17 1 171 ,產生[1,18,35,52,69,86,103,120,137,154,171]

從17年到1711111年由17歲計算

range 17 17 1711111 ,產生[17,34,51,68,85, ...

我也對本教程感到困惑:本教程使用了單詞step,沒有解釋,在我看來並不是我認為的一步。 然后它顯示了很容易被誤解的例子。 因為[2,4..20]看起來像是從4開始的第2步。

線索在輸出中:

ghci> [2,4..20]  
[2,4,6,8,10,12,14,16,18,20]

如果你仔細看(我沒有)。 它意味着從2開始,下一個是4,從(4 - 2)開始隱式步驟,繼續輸出數字,步長為2到最多20。

"ghci>" [1,6..20]
[1,6,11,16]

注意20不輸出,因為16 + 5大於20

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM