Uma solução barebones
Vamos começar com uma solução muito simples para imprimir uma essência de uma sequência. Ele não trata das especificidades que você adicionou à sua pergunta, mas é um bom ponto de partida:
sub seq-range-gist ( @seq ) {
my @pairs = @seq.pairs;
join "\n", @pairs.head(3)».gist, '...', @pairs.tail(2)».gist
}
Ao contrário .kv, o que converte seu invocante no formulário key1, value1, key2, value2, key3, value3, ..., ou seja, 6 elementos se o invocante contiver 3 elementos, .pairsconverte o invocante no formulário key1 => value1, key2 => value2, key3 => value3, ....
Eu usei em .pairsvez de em .kvparte porque isso significava que eu poderia usar ».gistmais tarde no código para obter uma key1 => value1exibição agradável para cada elemento sem esforço . Vamos modificar isso abaixo, mas este é um bom começo idiomático.
As chamadas .heade .tailsão a maneira idiomática de criar pequenas listas do primeiro e do último N elementos a partir de uma lista invocante (desde que não seja preguiçoso; mais sobre isso em breve).
Dada esta solução inicial, say seq-range-gist (0,1 ... Inf)[^10]exibe:
0 => 0
1 => 1
2 => 2
...
8 => 8
9 => 9
Em seguida, queremos poder "soltar apenas o primeiro elemento ... da saída impressa". Infelizmente say seq-range-gist (0,1 ... Inf)[1..9]exibe:
0 => 1
1 => 2
2 => 3
...
7 => 8
8 => 9
Queremos que o número à esquerda do =>retenha a numeração da sequência original. Para habilitar isso, dividimos a sequência subjacente do intervalo que queremos extrair. Nós adicionamos um segundo parâmetro / argumento @rangee anexamos [@range]à segunda linha do sub:
sub seq-range-gist ( @seq, @range ) {
my @pairs = @seq.pairs[@range];
Agora podemos escrever say seq-range-gist (0,1 ... Inf), 1..9para exibir:
1 => 1
2 => 2
3 => 3
...
8 => 8
9 => 9
Na sua pergunta, você usou o formato em aINDEX = VALUEvez de INDEX => VALUE. Para permitir a personalização da essência, adicionamos um terceiro &gistparâmetro / argumento de rotina e chamamos isso em vez do .gistmétodo incorporado :
sub seq-range-gist ( @seq, @range, :&gist ) {
my @pairs = @seq.pairs[@range];
join "\n", @pairs.head(3)».&gist, '...', @pairs.tail(2)».&gist
}
Observe como as invocações de "método" no corpo de seq-range-gistsub são agora .&gist, não .gist. A sintaxe .&foochama um sub &foo (que normalmente é chamado apenas por escrito foo), passando o invocante à esquerda do .como $_argumento para o sub.
Observe também que eu fiz o &gistparâmetro nomeado, precedendo-o com a :.
Então agora é say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" }exibido:
a1 = 1
a2 = 2
a3 = 3
...
a8 = 8
a9 = 9
Adicionando polonês
O restante desta resposta é um material bônus para os leitores que se preocupam com o polimento.
say seq-range-gist (0, 1, 2, 3), ^3 exibe:
0 => 0
1 => 1
2 => 2
...
1 => 1
2 => 2
Opa E mesmo que houvesse mais pares do que a cabeça e a cauda combinadas, pelo menos não tivéssemos linhas repetidas, ainda não faria sentido usar a head, ..., tailabordagem para eliminar apenas um ou dois elementos. Vamos alterar a última declaração no sub-corpo para eliminar esses problemas:
join "\n",
@pairs < $head + $tail + 3 # Of course, the 3 is a bit arbitrary
?? @pairs».&gist
!! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)
Em seguida, seria bom se o sub fizesse algo útil se chamado sem um intervalo ou essência. Podemos principalmente corrigir isso, fornecendo os parâmetros @rangee &gistpadrões adequados:
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:&gist = { .gist }
) {
Se não@seq for preguiçoso , o padrão será o intervalo completo de . Se for infinito (nesse caso, também é preguiçoso), o padrão de até 100 está bom. Mas e se for preguiçoso, mas produzir menos de 100 valores definidos? Para cobrir este caso, anexamos à declaração: @range@seq@seq@seq.grep: *.value.defined@pairs
my @pairs = @seq.pairs[@range].grep: *.value.defined;
Outra melhoria simples seria parâmetros opcionais de cabeça e cauda, levando a uma solução final polida:
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:$head = 3,
:$tail = 2,
:&gist = { .gist }
) {
my @pairs = @seq.pairs[@range].grep: *.value.defined;
join "\n",
@pairs <= $head + $tail + 2
?? @pairs».&gist
!! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)
}