Haskell(GHCi)的范围

iso*_*mes 31 haskell

我正在读" 为了好大学而学习你的哈斯克尔".他的例子 [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..]:

     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]
    
    Run Code Online (Sandbox Code Playgroud)

为什么?

Ant*_*sky 50

你有略微偏离范围的含义.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]   
Run Code Online (Sandbox Code Playgroud)

请注意,在第一种情况下,列表按两次计数,而在第二种情况下,列表按三次计算.那是因为第一和第二项之间的差异分别是两个和三个.在您的语法中,您正在尝试编写[first,step..last]以获取列表[first,first+step,first+2*step,...,last]; 但是,这样的范围的步长实际上是前两个数字之间的差异.没有第二个元素,步长总是一个; 如果没有最终元素,列表将永远持续(或直到达到类型的最大/最小元素).

因此,让我们看看你的三个例子:

  • [17,1..171] == [].既然你指定17,1,Haskell看到列表的前两个元素应该是17和1,所以你必须依靠-16.在这种情况下,Haskell想要在元素小于最后一个元素时立即停止---但它们以这种方式开始,因此不会产生任何元素.要计算一个,你想要[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对另一个问题有一个很好的答案.


fuz*_*fuz 12

那么,这些操作的语义与你期望的有点不同.该构造[a,b..c]实际上只是语法糖enumFromThenTo a b c,其行为有点像这样:

计算d = b - a.输出[a,b..c][a,a+d,a+d+d,a+d+d+d,...].这是重复的,直到a+n*d > c,如果d并且c - a具有不同的符号(在这种情况下,列表将是无限的,因此没有输出),或者直到maxBoundminBound达到,则输出结束.(当然,这是以不同的方式实现的,因为我们在Enum这里使用任意实例).

因此[1,3..10]变得[1,3,5,7,9]以来17 - 17 = 0,[17, 17..171111]产量[17,17+0,17+0+0...].通过这个稍微复杂的规则,[17, 1..171]产生空列表.

对于你的补充:[x,y..]是使用函数实现的,除了没有边界条件外enumFromThen x y,行为就像enumFromThenTo,所以如果你Enum是无限的,那么结果列表就是如此.