как пролистывать список бесконечно и лениво в Raku?

Это в основном для того, чтобы узнать, насколько хорош Raku.

Вопрос

Существуют ли встроенные методы, которые будут брать список и бесконечно перебирать его, создавая, скажем, ленивый список?

a, b, c, a, b, c, ...

из (a, b, c)? Очевидно, что ничто в документации по спискам явно не помогает.

Возможные решения

Я могу вспомнить хотя бы пару.

Более практичным и практичным методом было бы map @array[<variable> mod length-of-@array] в ленивом диапазоне 0..Inf. В perl6 REPL:

> my @ar=<a b c>
[a b c]
> (0..Inf).map({ @ar[$_ % @ar.elems] }).[0..100]
(a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a ...)

Более крутое (я думаю) решение - сначала превратить свой список в промах, а затем примените оператор повторения к этому промаху на неопределенный срок:

> my @ar=<a b c>
[a b c]
> (|@ar xx *).[0..100]
(a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a ...)

Заключение

Несмотря на то, что я могу добиться этого (и последнее решение, в частности, очень емкое и удовлетворительное), мне интересно, не хватает ли мне чего-либо, встроенного специально для этой цели.


Изменить Re: принятый ответ

Это нужно для того, чтобы немного уточнить ответ @Brad Gilbert. Оператор «~» оборачивает конкатенацию строк ~ в « » гипероператор, который приводит к применению обернутого двоичного оператора к элементам, выбранным последовательно из двух списков.

Итак, чтобы достичь того, что я хотел (цикл списка до желаемой длины, например, 100), можно было бы сделать

<a b c> <<~>> ("" xx 100)

Это производит

(a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a)

(100 записей). Однако у него есть несколько недостатков:

  • он переводит записи списка в строки из-за применения ~
  • на самом деле он не создает ленивый бесконечный список:
<a b c> <<~>> ("" xx *)

возвращается

List on right side of hyperop of infix:<~> is known to be infinite
  in block <unit> at <unknown file> line 1

person grobber    schedule 17.10.2020    source источник


Ответы (3)


Когда это можно написать так коротко, зачем добавлять функцию только для этого. Тем более, что это, наверное, редкий случай, когда вам понадобится такая вещь.

|< a b c > xx *

Что ж, есть одно исключение: если вы используете что-то вроде «~», оно расширяется за вас.

< a b c > «~» (1..10)
# (a1 b2 c3 a4 b5 c6 a7 b8 c9 a10)
person Brad Gilbert    schedule 17.10.2020
comment
Спасибо! Я согласен с мнением (что в конкретном операторе нет необходимости), но я рад, что спросил: вы предоставили решение, основанное на документах по спискам, которые я пропустил. Я принял ответ и отредактирую свой вопрос, включив в него некоторые ссылки. - person grobber; 17.10.2020
comment
Я понял, что это не дает бесконечного ленивого списка: см. Правку. Это нормально, поскольку я собираюсь использовать это только для выбора определенного количества записей. - person grobber; 17.10.2020
comment
(|< a b c > xx *)[0..99].put работает так же, как (|@ar xx *)[0..99].put - person jubilatious1; 07.03.2021

Не знаю, понял ли я проблему. Но я понял, что вам нужен метод для создания бесконечного списка по шаблону. Хорошо, если это проблема в книге, Think in Raku предлагает кое-что, что может помочь , в части 14.5 (адаптировано из того, как построить последовательность Фибоначчи)

("a","b","c", -> $a, $b, $c {$a} ...* )

этот элемент является чистым списком, если вам нужны значения извлечения, вам нужно что-то вроде более обычного в списке (например, назначать и извлекать значения)

my @list = ("a","b","c", -> $a, $b, $c {$a} ...* )
@list[0..100]
@list[91]

Я думаю, что использовать карту в контексте Inf - плохая идея, но скажите, пожалуйста, если я что-то пропустил, я все еще изучаю этот замечательный язык !!

person metagib    schedule 19.10.2020
comment
большое спасибо, но я хотел, чтобы это работало для произвольных списков вместо вашего "a","b","c". Так что я бы предложил my @inf_list=(|@orig_list, sub (*@ar) { @ar[*-@orig_list] } ...*) - person grobber; 20.10.2020
comment
Оооо, теперь я понимаю, что у вашего метода есть преимущество инкапсуляции как метода для использования с любым списком. Хорошо, переформулируйте мои ответы, я думаю, будет более ясным, сгладьте список и повторите его сглаженным my @list = <a 2 v c>; my @inf_list = (|@list, -> {|@list} ...* ) - person metagib; 21.10.2020
comment
Справедливо, но тогда стрелка не нужна -> :) - person grobber; 21.10.2020

Ваш первый практический пример можно записать как (^Inf).map({ @ar[$_ % *] })

Кроме того, скольжение и повторение работают нормально, но только для списков разумного размера.

sub bad-cycle(@xs) {
    |@xs xx Inf
}

my $big-list = ^1e6;
say bad-cycle($big-list).head(100);    # Hangs for several seconds

Лучшим вариантом будет карта, подобная показанной выше, или цикл gather, подобный этому.

sub cycle(@xs) {
    gather loop { .take for @xs }
}

say cycle($big-list).head(100);    # Instant output
person Joshua    schedule 19.10.2020