Должен ли я рассчитывать на Perl 6 с последовательностью или диапазоном?
Perl 6 имеет ленивые списки, но также имеет неограниченные Range объекты. Какой из них следует выбрать для подсчета по целым числам?
И там неограниченный Range с двумя точками:
0 .. *
Здесь Seq (последовательность) с тремя точками:
0 ... *
A Range
генерирует списки целых объектов, используя их естественный порядок. Он наследует от Iterable, а также Positional, чтобы вы могли индексировать диапазон. Вы можете проверить, находится ли что-то в пределах Range
, но это не является частью задачи.
A Seq
может генерировать только что угодно, если только он знает, как перейти к следующему элементу. Он наследует от Iterable, но также PositionalBindFailover, который подделывает содержимое Positional
через кеш и преобразование списка. Я не думаю, что это очень важно, если вы только переходите от одного элемента к другому.
Я собираюсь туда и обратно. На данный момент я думаю об этом Range.
Ответы
Ответ 1
Семантически, a Range
- статическая вещь (ограниченный набор значений), a Seq
- динамическая вещь (генератор значений) и ленивый List
статический вид динамической вещи ( неизменяемый кеш для генерируемых значений).
Правило большого пальца: Предпочитайте статическое по динамике, но просто над сложным.
Кроме того, a Seq
является итерируемой вещью, a List
является итерируемой позиционной вещью, а Range
является упорядоченной итерируемой позиционной вещью.
Правило большого пальца: перейдите с наиболее общим или конкретным в зависимости от контекста.
Поскольку мы имеем дело только с итерацией и не заинтересованы в позиционном доступе или границах, использование Seq
(по существу, в коробке Iterator
) кажется естественным выбором. Однако упорядоченные наборы последовательных целых чисел являются именно тем, что представляет собой целое число Range
, и лично, что я считаю наиболее подходящим для вашего конкретного случая использования.
Когда нет четкого выбора, я предпочитаю диапазоны для их простоты в любом случае (и старайтесь избегать ленивых списков, тяжелых).
Обратите внимание, что синтаксис языка также подталкивает вас в направлении Range
, которые довольно сильно закодированы по Хаффману (два-char infix ..
, one- char prefix ^
).
Ответ 2
Оба 0 .. *
и 0 ... *
в порядке.
- Итерация по ним, например, с циклом
for
, имеет одинаковый эффект в обоих случаях. (Также не будет утечка памяти, сохранив уже итерированные элементы.)
- Присвоение их переменной
@
создает тот же ленивый массив.
Итак, пока вы хотите только подсчитать числа до бесконечности на шаг 1, я тоже не вижу недостатка.
Оператор построения последовательности ...
более общий, поскольку он также может использоваться для
- подсчет с другим шагом (
1, 3 ... *
)
- считать вниз (
10 ... -Inf
)
- следовать геометрической последовательности (
2, 4, 8 ... *
)
- следуйте специальной формуле итерации (
1, 1, *+* ... *
)
поэтому, когда мне нужно сделать что-то подобное, я бы подумал использовать ...
для любого соседнего и связанного "подсчета вверх одним", а также для согласованности.
С другой стороны:
- A
Range
может быть эффективно проиндексирован без необходимости генерации и кэширования всех предыдущих элементов, поэтому, если вы хотите индексировать свой счетчик в дополнение к итерации по нему, это предпочтительнее. То же самое касается других операций с списками, которые занимают позиции элементов, например reverse
: Range
имеет эффективные перегрузки для них, тогда как использование их в Seq
должно сначала итерировать и кэшировать его элементы.
- Если вы хотите подсчитать вверх до переменной конечной точки (как в
1 .. $n
), безопаснее использовать Range
, потому что вы можете быть уверены, что он никогда не будет считать вниз, независимо от того, что $n
, (Если конечная точка меньше начальной точки, как в 1 .. 0
, она будет вести себя как пустая последовательность при повторении, которая на практике имеет тенденцию к краю дел).
И наоборот, если вы хотите безопасно рассчитывать вниз, чтобы он никогда не подсчитывал вверх, вы можете использовать reverse 1 .. $n
.
- Наконец, a
Range
является более конкретным/высокоуровневым представлением понятия "числа от x до y", тогда как a Seq
представляет собой более общее понятие "последовательность значений". A Seq
в общем случае управляется произвольным кодом генератора (см. gather
/take
) - оператор ...
- это просто семантический сахар для создания некоторые общие типы последовательностей. Таким образом, может показаться более декларативным использование диапазона, когда "цифры от x до y" - это концепция, которую вы хотите выразить. Но я полагаю, что это чисто психологическая проблема...: P
Ответ 3
Существует разница между ".." (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 должен быть прекрасным выбором.