我应该在 Perl 6 中使用序列还是范围来计数?
Should I count up in Perl 6 with a sequence or a range?
Perl 6 有 lazy lists, but it also has unbounded Range 个对象。你应该选择哪一个来计算整数?
并且有两个点的无限 Range:
0 .. *
有三个点的Seq (sequence):
0 ... *
A Range
使用自然顺序生成连续事物的列表。它继承自 Iterable, but also Positional,因此您可以索引一个范围。您可以检查 Range
中是否有内容,但这不是任务的一部分。
A Seq
可以生成任何你喜欢的东西,只要它知道如何到达下一个元素。它继承自 Iterable, but also PositionalBindFailover,后者通过缓存和列表转换伪造 Positional
内容。如果您只是从一个元素移动到下一个元素,我认为这没什么大不了的。
我要来回讨论这个问题。目前我认为是 Range.
“..”(Range)和“...”(Seq)有区别:
$ perl6
> 1..10
1..10
> 1...10
(1 2 3 4 5 6 7 8 9 10)
> 2,4...10
(2 4 6 8 10)
> (3,6...*)[^5]
(3 6 9 12 15)
“...”运算符可以凭直觉判断模式!
https://docs.perl6.org/language/operators#index-entry-..._operators
据我了解,您只能遍历一个 Seq 一次。它适用于您不需要返回的流式传输(例如,文件)。我认为 Range 应该是一个不错的选择。
0 .. *
和 0 ... *
都可以。
- 迭代它们,例如使用
for
循环,在这两种情况下具有完全相同的效果。 (两者都不会通过保留已经迭代的元素来泄漏内存。)
- 将它们分配给一个
@
变量会产生相同的惰性数组。
因此,只要您只想以 1 为步长将数字累加到无穷大,我认为两者都没有缺点。
...
序列构造运算符更通用,因为它也可以用于
- 用不同的步骤计数 (
1, 3 ... *
)
- 倒数 (
10 ... -Inf
)
- 遵循几何序列 (
2, 4, 8 ... *
)
- 遵循自定义迭代公式 (
1, 1, *+* ... *
)
所以当我需要做类似的事情时,为了保持一致性,我会考虑对任何附近和相关的 "count up by one" 使用 ...
。
另一方面:
- A
Range
可以高效地索引,而不必生成和缓存所有前面的元素,因此如果除了迭代它之外还想索引计数器,这是更可取的。处理元素位置的其他列表操作也是如此,例如 reverse
:Range
对它们具有高效的重载,而在 Seq
上使用它们必须首先迭代并缓存其元素。
- 如果你想向上计数到可变终点(如
1 .. $n
),使用 Range
更安全,因为你可以确定它永远不会向下计数,不不管 $n
是什么。 (如果端点小于起点,如 1 .. 0
,迭代时它将表现为一个空序列,这在实践中往往会得到正确的边缘情况。)
相反,如果你想安全地向下计数确保它永远不会意外地向上计数,你可以使用 reverse 1 .. $n
.
- 最后,
Range
是 "numbers from x to y" 概念的更 specific/high-level 表示,而 Seq
表示 "a sequence of values" 更通用的概念.通常,Seq
由任意生成器代码驱动(参见 gather
/take
)- ...
运算符只是用于创建一些常见类型序列的语义糖。因此,当 "numbers from x to y" 是您想要表达的概念时,使用 Range 可能会让人感觉更具声明性。但我想这纯粹是心理问题... :P
从语义上讲,一个Range
是一个静态的东西(一组有界值),一个Seq
是一个动态的东西(一个值生成器)和一个惰性的List
一个动态事物的静态视图(生成值的不可变缓存)。
经验法则: 静态优于动态,简单优于复杂。
另外,Seq
是可迭代的东西,List
是可迭代的位置的东西,Range
是有序的可迭代的位置的东西。
经验法则: 根据上下文选择最通用或最具体的。
因为我们只处理迭代并且对位置访问或边界不感兴趣,所以使用 Seq
(本质上是一个盒装的 Iterator
)似乎是一个自然的选择。但是,有序的连续整数集 恰好 整数 Range
所代表的内容,就我个人而言,这就是我认为最适合您的特定用例的内容。
当没有明确的选择时,我倾向于选择范围,因为它们的简单性(并尽量避免重量级的懒惰列表)。
请注意,语言语法也会将您推向 Range
的方向,这些语法是相当严重的霍夫曼编码(两个字符中缀 ..
,一个字符前缀 ^
).
Perl 6 有 lazy lists, but it also has unbounded Range 个对象。你应该选择哪一个来计算整数?
并且有两个点的无限 Range:
0 .. *
有三个点的Seq (sequence):
0 ... *
A Range
使用自然顺序生成连续事物的列表。它继承自 Iterable, but also Positional,因此您可以索引一个范围。您可以检查 Range
中是否有内容,但这不是任务的一部分。
A Seq
可以生成任何你喜欢的东西,只要它知道如何到达下一个元素。它继承自 Iterable, but also PositionalBindFailover,后者通过缓存和列表转换伪造 Positional
内容。如果您只是从一个元素移动到下一个元素,我认为这没什么大不了的。
我要来回讨论这个问题。目前我认为是 Range.
“..”(Range)和“...”(Seq)有区别:
$ perl6
> 1..10
1..10
> 1...10
(1 2 3 4 5 6 7 8 9 10)
> 2,4...10
(2 4 6 8 10)
> (3,6...*)[^5]
(3 6 9 12 15)
“...”运算符可以凭直觉判断模式!
https://docs.perl6.org/language/operators#index-entry-..._operators
据我了解,您只能遍历一个 Seq 一次。它适用于您不需要返回的流式传输(例如,文件)。我认为 Range 应该是一个不错的选择。
0 .. *
和 0 ... *
都可以。
- 迭代它们,例如使用
for
循环,在这两种情况下具有完全相同的效果。 (两者都不会通过保留已经迭代的元素来泄漏内存。) - 将它们分配给一个
@
变量会产生相同的惰性数组。
因此,只要您只想以 1 为步长将数字累加到无穷大,我认为两者都没有缺点。
...
序列构造运算符更通用,因为它也可以用于
- 用不同的步骤计数 (
1, 3 ... *
) - 倒数 (
10 ... -Inf
) - 遵循几何序列 (
2, 4, 8 ... *
) - 遵循自定义迭代公式 (
1, 1, *+* ... *
)
所以当我需要做类似的事情时,为了保持一致性,我会考虑对任何附近和相关的 "count up by one" 使用 ...
。
另一方面:
- A
Range
可以高效地索引,而不必生成和缓存所有前面的元素,因此如果除了迭代它之外还想索引计数器,这是更可取的。处理元素位置的其他列表操作也是如此,例如reverse
:Range
对它们具有高效的重载,而在Seq
上使用它们必须首先迭代并缓存其元素。 - 如果你想向上计数到可变终点(如
1 .. $n
),使用Range
更安全,因为你可以确定它永远不会向下计数,不不管$n
是什么。 (如果端点小于起点,如1 .. 0
,迭代时它将表现为一个空序列,这在实践中往往会得到正确的边缘情况。)
相反,如果你想安全地向下计数确保它永远不会意外地向上计数,你可以使用reverse 1 .. $n
. - 最后,
Range
是 "numbers from x to y" 概念的更 specific/high-level 表示,而Seq
表示 "a sequence of values" 更通用的概念.通常,Seq
由任意生成器代码驱动(参见gather
/take
)-...
运算符只是用于创建一些常见类型序列的语义糖。因此,当 "numbers from x to y" 是您想要表达的概念时,使用 Range 可能会让人感觉更具声明性。但我想这纯粹是心理问题... :P
从语义上讲,一个Range
是一个静态的东西(一组有界值),一个Seq
是一个动态的东西(一个值生成器)和一个惰性的List
一个动态事物的静态视图(生成值的不可变缓存)。
经验法则: 静态优于动态,简单优于复杂。
另外,Seq
是可迭代的东西,List
是可迭代的位置的东西,Range
是有序的可迭代的位置的东西。
经验法则: 根据上下文选择最通用或最具体的。
因为我们只处理迭代并且对位置访问或边界不感兴趣,所以使用 Seq
(本质上是一个盒装的 Iterator
)似乎是一个自然的选择。但是,有序的连续整数集 恰好 整数 Range
所代表的内容,就我个人而言,这就是我认为最适合您的特定用例的内容。
当没有明确的选择时,我倾向于选择范围,因为它们的简单性(并尽量避免重量级的懒惰列表)。
请注意,语言语法也会将您推向 Range
的方向,这些语法是相当严重的霍夫曼编码(两个字符中缀 ..
,一个字符前缀 ^
).