首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Haskell的范围(GHCi)

Haskell的范围(GHCi)
EN

Stack Overflow用户
提问于 2011-10-31 18:46:50
回答 4查看 35.4K关注 0票数 42

我在读为伟大的善学一只Haskell他的例子 [2,2..20][3, 6..20]工作得很好,但我得到了三个奇怪的结果:

  1. 计数17从1到171:[17, 1..171]生成空列表。
  2. 从17数到1711111:[17, 17..171111]重复数字17,直到我中断GHCi为止。
  3. take 54 [171, 234..]take 54 [171, 244..]之间有一个奇怪的区别: ghci>采取54171,234个.ghci>走54171,244..。

为什么?

EN

回答 4

Stack Overflow用户

发布于 2011-10-31 19:05:25

你的意思是范围略有偏离。Haskell范围语法是四样东西之一:[first..][first,second..][first..last][first,second..last]。来自http://learnyouahaskell.com/starting-out#texas-ranges的示例包括

代码语言:javascript
复制
ghci> [2,4..20]  
[2,4,6,8,10,12,14,16,18,20]  
ghci> [3,6..20]  
[3,6,9,12,15,18]   

注意,在第一种情况下,列表计数为2,而在第二种情况下,列表计数为3。这是因为第一项和第二项的区别分别是两项和三项。在您的语法中,您试图编写[first,step..last]以获得列表[first,first+step,first+2*step,...,last];然而,这样的范围的步骤大小实际上是前两个数字之间的区别。没有第二个元素,步骤大小总是一个;没有最后一个元素,列表将永远继续(或者直到达到类型的最大/最小元素)。

因此,让我们看看您的三个示例:

  • [17,1..171] == []。由于您指定了17,1,Haskell看到列表的前两个元素应该是17个和一个,所以您必须使用-16进行计数。在这种情况下,Haskell想在元素比最后一个元素更小的时候停止--但是它们是这样开始的,所以不会产生任何元素。要数到1,您需要[17,18..171] (列表的前两个元素是17和18),或者简单地说是[17..171]
  • [17, 17..171111] == repeat 17。这个很有趣。由于列表中的前两个元素都是17,所以Haskell确定您必须以零来计数,并且它将很高兴地继续计数,直到结果超过171111为止。当然,当计数为零时,这是永远不会发生的,所以你会得到一个无限的十七人的列表。如果你认为这样做更清楚的话,要想在17岁前数数,你需要[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),那么您只需要请求前54个元素。

关于范围语法的一些细节(在Enum类型类中转换为函数),包括对浮点数范围的稍微令人惊讶的行为,汉玛尔对另一个问题有一个很好的答案。

票数 68
EN

Stack Overflow用户

发布于 2011-10-31 19:04:50

嗯,这些操作的语义与您的预期有点不同。构造[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,如果dc - 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是无限的,那么结果列表也是如此。

票数 13
EN

Stack Overflow用户

发布于 2016-03-25 13:31:31

我也对这种行为感到有点惊讶,所以我编写了一个对我来说更自然的范围函数(也许对你也是如此):

代码语言:javascript
复制
range step start end = takeWhile (<=end) $ iterate (+step) start

列举你的例子:

从一数到一百七十一。

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

从17点到1711111点。

range 17 17 1711111完成,生成[17,34,51,68,85, ...

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7958181

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档