Una solución básica
Comencemos con una solución muy simple para imprimir la esencia de una secuencia. No trata los detalles que ha agregado a su pregunta, pero es un buen punto de partida:
sub seq-range-gist ( @seq ) {
my @pairs = @seq.pairs;
join "\n", @pairs.head(3)».gist, '...', @pairs.tail(2)».gist
}
A diferencia .kv, lo que convierte su invocante en la forma key1, value1, key2, value2, key3, value3, ..., es decir, 6 elementos si su invocante contiene 3 elementos, .pairsconvierte su invocante en la forma key1 => value1, key2 => value2, key3 => value3, ....
Lo usé en .pairslugar de en .kvparte porque significaba que podría usarlo ».gistmás adelante en el código para obtener sin esfuerzo una buena key1 => value1visualización de cada elemento. Lo modificaremos a continuación, pero este es un buen comienzo idiomático.
Las llamadas .heady .tailson la forma idiomática de crear pequeñas listas de los primeros y últimos N elementos de una lista de invocadores (siempre que no sea vago; más sobre eso en un momento).
Dada esta solución inicial, say seq-range-gist (0,1 ... Inf)[^10]muestra:
0 => 0
1 => 1
2 => 2
...
8 => 8
9 => 9
A continuación, queremos poder "soltar solo el primer elemento ... de la salida impresa". Desafortunadamente say seq-range-gist (0,1 ... Inf)[1..9]muestra:
0 => 1
1 => 2
2 => 3
...
7 => 8
8 => 9
Queremos que el número a la izquierda del =>retenga la numeración de la secuencia original. Para habilitar esto, dividimos la secuencia subyacente del rango que queremos extraer. Agregamos un segundo parámetro / argumento @range, y agregamos [@range]a la segunda línea del sub:
sub seq-range-gist ( @seq, @range ) {
my @pairs = @seq.pairs[@range];
Ahora podemos escribir say seq-range-gist (0,1 ... Inf), 1..9para mostrar:
1 => 1
2 => 2
3 => 3
...
8 => 8
9 => 9
En su pregunta, utilizó el formato en aINDEX = VALUElugar de INDEX => VALUE. Para permitir la personalización de la esencia, agregamos un tercer &gistparámetro / argumento de rutina e invocamos eso en lugar del .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 cómo las invocaciones de "método" en el cuerpo de seq-range-gistsub son ahora .&gist, no .gist. La sintaxis .&fooinvoca un sub &foo (que generalmente se invoca escribiendo solo foo), pasando el invocante a la izquierda del .como un $_argumento para el sub.
Tenga en cuenta también que he hecho que el &gistparámetro tenga un nombre precediéndolo con un :.
Entonces ahora say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" }muestra:
a1 = 1
a2 = 2
a3 = 3
...
a8 = 8
a9 = 9
Agregar esmalte
El resto de esta respuesta es material adicional para los lectores que se preocupan por el esmalte.
say seq-range-gist (0, 1, 2, 3), ^3 muestra:
0 => 0
1 => 1
2 => 2
...
1 => 1
2 => 2
Ups E incluso si hubiera más pares que la cabeza y la cola combinados, por lo que al menos no obtuvimos líneas repetidas, aún sería inútil usar el head, ..., tailenfoque para eludir solo uno o dos elementos. Cambiemos la última declaración en el sub cuerpo para eliminar estos 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)
A continuación, sería bueno que el submarino hiciera algo útil si se llama sin un rango o esencia. Sobre todo que podemos arreglar que al dar a las @rangey &gistlos parámetros por defecto adecuados:
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:&gist = { .gist }
) {
Si no@seq es perezoso , el valor predeterminado es el rango completo de . Si es infinito (en cuyo caso también es vago), entonces el valor predeterminado de hasta 100 está bien. Pero, ¿qué pasa si es perezoso pero produce menos de 100 valores definidos? Para cubrir este caso, adjuntamos a la declaración: @range@seq@seq@seq.grep: *.value.defined@pairs
my @pairs = @seq.pairs[@range].grep: *.value.defined;
Otra mejora simple serían los parámetros opcionales de cabeza y cola, lo que llevaría a una solución final pulida:
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)
}