设计理想范围文字


10

我一直在思考如果要设计一种语言,我将如何设计“完美”范围文字。对于您不知道的语句中的范围文字,它表示一个值范围,例如1-4。它们最常用于for / foreach循环

似乎应该考虑几个问题

  • 支持包含范围和排除范围,将+1或-1附加到端点似乎有点笨拙且容易出错。

  • 支持步进,因此您可以设置例如偶数或奇数范围

  • 可读性,范围文字描述的内容应该显而易见

  • 明确,范围文字所描述的内容应该完全明确

  • 默认值可能是从包含值到排除值,因为在大多数情况下,这是用于遍历数组等的方式。

无论如何,我所见过的范围文字的一个示例是Ruby,其形式为1..3表示排他性(最后),1 ... 3表示排他性(最后)。您也可以执行1..10.step(5)。经过仔细考虑后,我发现该方法有一些我不喜欢的地方(从我对红宝石的有限了解)

  1. 您只能在最后描述包含式和排除式。在描述大多数情况时,它似乎并不一致。

  2. 仅需额外增加一个。似乎是使难以看清范围是包含范围还是排除范围的秘诀。我不了解你,但是点变得模糊起来了:)

  3. 为范围添加表示法之类的方法似乎将文字的概念与类的概念混合在一起,这似乎有点不一致(即使将范围编译为一个类)

无论如何,在考虑其他选择之后。我想出了这个

  • [5..1] 5,4,3,2,1
  • [1..5 [ 1,2,3,4
  • ] 1..5] 2,3,4,5
  • [ 0..5..20] 0,5,10,15,20

等等。我喜欢它,因为[通常会否定一个集合,即使这样与集合形成对比,它也很适合。

我有点担心的一件事是使排他性/包含性指示符是否强制性,即,如果只写1..5,则默认值为1,2,3,4,因为这是数组等的最常见情况。 。它更容易阅读,但更具针对性,如果您不得不写[1..5 [您会早日了解它们的工作原理。

那么,您认为我涵盖了大多数基础,却忽略了某些内容吗?您会否使[]为强制性?您会在编程语言中设计范围文字吗?

候选人

  • 括号样式:[0..10 [ ,带有步骤: [0..5..20 [
  • 间隔符号:[0..10) ,步长:[0..5..20)
  • 感叹为排他。0 ..!10,含步骤:0..5 ..!20
    • 不同的步骤。0 ..!20,5
    • 但是,这将使默认值* 0..10'包含在内
  • 罗:[0至!20 x 5]

我必须说,到目前为止,我最喜欢的是0 ..!100..5 ..!20,我只希望默认值0..10成为包容性-独占会更合逻辑


2
1,5,10,15,20缺口4,5,5,5 ?!
彼得·泰勒

oops :)更正
Homde

Answers:


14

为什么要发明数学中已经存在的东西?

间隔符号

那应该涵盖您已经存在的“明确性”点。

您唯一的问题是定义步进。也许数学上的其他东西可以帮上忙吗?


3
嗨,我实际上是关于间隔符号。但是,让我不想使用它的原因是它与[和)都不对称,并且使用了括号,并且没有步骤(如您所述)。使用括号可能会混淆花括号匹配,我宁愿将它们保存到表达式中。使用]和[是一个iso标准,似乎可以更好地集成步进,但这只是我的意见。
霍姆德2011年

7
@MKO:您使用不匹配的方括号(如[1..5[)的想法至少会使编辑器与标准间隔符号混淆。
David Thornley

2
嗯,另一个想法,使用!例如:1 ..!5或0..5 ..!20(带步进)
洪德堡2011年

1
@MKO:使用!排除第一个或最后一个元素可能会很好。
FrustratedWithFormsDesigner

8

您看到过Haskell靶场吗?他们关于步骤的想法与您(在中间)类似,但是在语法上有所不同(来自@luqui的答案):

[1,2..10] = [1,2,3,4,5,6,7,8,9,10]
[1,3..10] = [1,3,5,7,9]
[4,3..0]  = [4,3,2,1,0]
[0,5..]   = [0,5,10,15,20,25,30,35...  -- infinite
[1,1..]   = [1,1,1,1,1,1,1,1,1,1,1...  -- infinite

我发现这种表示法非常直观:您开始枚举并跳过正文以标记它应在哪里结束。

它没有涵盖“排他”的情况,但是坦率地说,我宁愿一次了解一下行为(指定哪个边界是包含的,哪个边界是排他的),并希望用户进行调整,除非语法非常清楚(并且不会混淆与语言无关的编辑器)。


5

您应该阅读有关提供列表理解的语言。

例如,Python使用range()功能和列表理解很好地覆盖了您的案例,以解决用太复杂的案例range()


2

我相信您的表达方式绝不会模糊不清。[0..5..20]凭直觉,在我看来不像步长= 5的范围。在某些极端情况下,它甚至会失败:如何表达集合(0,2)-[0..2..2]怎么办?或者我应该放在中间?

我认为Python的切片符号是一种可靠的方法: [start:end:step]步骤是可选的)。

如果您确实需要对排他和包含范围的支持,那么我将使用标准范围表示法(即使用([),除非这在您的语言中引入了句法歧义。


1
关于“标准”的符号,欧洲的学校任教[][[]]][,没有括号......和我们的标准是比较好,当然;)
马修M.

@Matthieu:其实,这里是荷兰(这在欧洲),我们也告诉我们,标准的符号。
弗里茨

1

我认为,当您设置第三个增量值时,最好将其添加到末尾而不是中间,因为这是一个可选值,对于经验丰富的程序员来说,比在中间添加一个可选的第3个参数更直观。

因此,您可以执行[1..20] [5]或[1..20,5]代替[1..5..20]


这是一个正确的观点,也许是一个品味的问题,在我看来,使用[1..20]来思考“ 1步5到20”比“ 1步从2到5,更容易”。 [5]似乎有点混乱,但逗号方法可能是可行的。我希望能收到更多反馈
Homde 2011年

1
  • [1..5 [1,2,3,4
  • ] 1..5] 2,3,4,5
  • ] 1..5 [2,3,4

为什么不只使用[1..4],[2..5],[2..4]?排除范围不会带来太多好处。您不需要写MIN + 1或MAX-1,是的,但是无论如何它们都不禁止写。太多的变化,恕我直言。我选择的语言scala具有(1到3)和(1到3)[=(1到2)],但是一开始它只是让我感到困惑。现在,我总是使用'​​x to y',因此知道,我不使用的选项是排除选项,但是我当然不会从不使用的选项中受益。

  • [5..1] 5,4,3,2,1

当然是(1到MAX)(x => y =(MAX + 1)-x),但这很容易理解,而且不方便使用。

  • [0..5..20] 0,5,10,15,20

当然(0到4)(x => y = x * 5)并不是很多样板。有争议。


排除范围的主要好处afaik,是元素的数量是端点的差。
Justin L.

@JustinL:图5-1是在我的代数4,但包含3个元素,不包括边界:2,3,4,
用户未知

1

像这样的事情呢:

  • [5..1] 5,4,3,2,1
  • [1..5] [i,e] 1,2,3,4
  • [5..1] [i,e] 5,4,3,2
  • [1..5] [e,i] 2,3,4,5
  • [1..5] [e,e] 2,3,4
  • [0..20]乘5 0,5,10,15,20

ie第二组方括号表示如果的游戏内或范围的结尾是包括或不包括(或者你可以使用incl,而excl如果你想更清楚)。的by 5指示步进间隔。第一个和最后一个示例包含第一个和最后一个值,因此我省略了[i,i],我认为这是可以接受的默认行为。

缺省值可以是[i,i]包含/排除说明符,并且by 1步骤说明符的。

通常,我会建议@Dan McGrath提及(并涉及的标准符号[,但是我同意在代码中这可能会造成混淆。


谁能解释不赞成票?
FrustratedWithFormsDesigner

我没有发现明显的错误。我投票反对那票。
Berin Loritsch 2011年

1

最终获胜者是

很抱歉选择我自己的解决方案,我非常感谢所有评论和反馈,如果发现任何问题,请批评一下此解决方案

所以我决定去:

0..5           = 0,1,2,3,5
0..5..10       = 0,5,10
..3            = 0,1,3
!0..!5         = 1,2,3,4
3..            = 3 to infinity

segmented ranges
-
0..5,..5..20   = 0,1,2,3,4,5,10,15,20
0..3,10..5..20 = 0,1,2,3,10,15,20

如您所见,包容性是两种感觉的默认设置,这是直观上最有意义的东西,尤其是在使用步进时。您可以使用 !结束独家报道。

不利之处在于,通常情况下,在处理数组时,您希望使用独占方式,但是在大多数情况下,大多数情况下,您可能应该使用for-each之类的东西。如果您确实确实需要对索引进行处理,那么解析器可以识别出何时您可能最终忘记了排除标记并发出警告

我继续在step变量的两边使用..而不是使用逗号或其他任何东西,因为这看起来最干净,我希望它是最易读的。

我还用逗号添加了一些语法,以便能够确定不同部分具有不同步骤的范围


似乎可以,除非指定了步骤。我认为将[0..10 x 5]设为整洁。分段范围可以是[0..5,.. 20除以5],等等。还可以指定[从第一步开始的数字],(与其他形式不同)该步长可以为零。
supercat 2014年

0

出于避免混合使用括号和花括号的相同原因之一,我不会使用“ [1..5 [”格式-这会混淆大多数现有编辑器的花括号匹配。也许在括号内使用标记,例如“ [1 .. | 5]”。

要考虑的另一件事是获得限制的方法的行为。例如,“开始” /“结束”与“第一” /“最后”与“最小” /“最大”。对于包含性和排除性限制以及步长限制,它们都必须保持理智。


0

Ruby具有表示法,并且可以使用Range对象。本质上看起来像这样:

1..5  # range 1,2,3,4,5

对于Ruby,步长大小不是范围的函数,而是迭代范围的函数。如果我们想要,我们可以使用上面相同的范围,并以不同的方式遍历它:

(1..5).step(3) { |x| puts x }
(1..5).step(2) { |x| puts x }

因此,您可能需要考虑以下事项:

  • 为包含/排除端点添加语言支持可能会出现问题。如果所有范围都包含在内(Ruby的选择),那么开发人员将相应地调整范围的端点。您如何以简单解析器语法在视觉上和歧义上都表示端点的包含性或排他性?
  • 您是否将范围用于迭代之外?常见示例包括范围比较,拼接,范围比较中的值。如果是这样,您如何代表这些可能性?(有关每个示例的想法,请参见Range类的链接。)

顺便说一句,如果您允许它们像Ruby那样包含在switch语句中,则范围是相当不错的:

switch(myval)
    when 0..33 then puts "Low"
    when 34..66 then puts "Medium"
    when 67..100 then puts "High"
end

我并不是说Ruby的range对象是最终目标,而是所有您正在谈论的概念的有效实现。试一试,看看您喜欢什么,不喜欢什么,并且会做不同的事情。


仔细阅读问题,OP 已经了解Ruby范围:Anyways, one example of range literal I've seen is Ruby which is in the form of 1..3 for an exclusive (on the end) range and 1...3 for inclusive (on the end). You can also do 1..10.step(5).
FrustratedWithFormsDesigner

0

我肯定会考虑的一种解决方案是使用运算符重载来允许例如

1+[0..3]*5

它不一定对每个人都是立即透明的,但是一旦他们停下来并认为我希望大多数程序员都能理解它,并且经常使用该语言的人就会把它作为一种习语来学习。

为了明确起见,结果将是[1, 6, 11, 16],在范围内提升乘法,然后进行加法。我还没有意识到它可能对Python用户是模棱两可的。我认为范围是总订单的子集,而不是列表。重复一组没有意义。


2
很am昧。list expression * 5也可能意味着“重复list expression5倍的值”,就像在Python中那样。
nikie 2011年

这看起来很奇怪,我不确定这会是什么... 1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,31,3,6,9,125,10,15?也许还有其他东西吗?无论哪种方式,我都发现这种表示完全违反直觉。看起来好像是某种奇怪的C指针操作...
FrustratedWithFormsDesigner
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.