Cómo crear una captura dinámicamente (Raku)

8

En el siguiente ejemplo, trato de crear una captura dinámicamente "convirtiendo" una matriz (@a) en una captura.

Considera el código:

sub f (|c){
    say '';
    say '  List : ' ~ do {c.list.gist if c.list.elems > 0};
    say '  Hash : ' ~ do {c.hash.gist if c.hash.elems > 0};
    say '';
}

my $c1 = \(1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9);

my @a  =   1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9;
my $c2 = \(|@a);

f(|$c1);

f(|@a);
f(|$c2);

El resultado es:

  List : (1 (2 3) 4 5 6 7 8 9)
  Hash : Map.new((t1 => test1, t2 => test2))


  List : (1 (2 3) 4 5 t1 => test1 6 7 t2 => test2 8 9)
  Hash : 


  List : (1 (2 3) 4 5 t1 => test1 6 7 t2 => test2 8 9)
  Hash : 

La primera ejecución (con Capture $ c1) se ejecuta como debería, produciendo el comportamiento deseado. El segundo y tercer intento, para crear una Captura dinámicamente, están fallando (probablemente porque el argumento de la subrutina f en esos casos NO es la Captura deseada). Observo que los pares incorporados en la matriz @a, se consideran miembros de una lista y NO parámetros nombrados como yo quería que fueran.

Sé que debe haber, más o menos, un "aplanamiento" de los pares en la matriz, antes de pasar a la subrutina f, ¡pero NO puedo encontrar la manera de hacerlo!

¿Alguien puede darme una pista?

jakar
fuente

Respuestas:

7

En la clase Listestá el método Capture, que funciona exactamente como quieres:

my $c  = \(1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9);
my @a  =   1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9;
my $c2 = @a.Capture;
f(|$c);
f(|$c2);
f(|@a);
sub f (|c){
    say() ;
    say '  List : ', c.List;
    say '  Hash : ', c.Hash;
    say();
}

Puede modificar la definición de la función fpara trabajar directamente con la lista @a.

my $c  = \(1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9);
my @a  =   1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9;
f($c);
f(@a);
sub f (Capture(Any) \c){
    say() ;
    say '  List : ', c.List;
    say '  Hash : ', c.Hash;
    say();
}

Capture(Any)es el llamado tipo de coerción . Acepta Anypero coacciona Capture, es decir, llama (repetidamente) al método Capturepara obtenerlo.

Además, Capturepuede utilizar la coincidencia de patrones. Así, la última definición de la función fpodría cambiarse a:

sub f ( (**@list, *%hash) ) {
#or even sub f ( (*@list, :t1($t),*%hash) ) {
    say() ;
    say '  List : ', @list;
    # say ' test1 : ', $t;
    say '  Hash : ', %hash;
    say();
}  
wamba
fuente
¿Puedes explicar un poco más por qué funciona tu segunda solución?
jakar
1
Agregué una explicación al final de mi respuesta.
wamba
Si está usando Foo(Any)como tipo, probablemente pueda usarlo Foo(). No me puedo imaginar un momento en el que tomaría una Anypero no un noAny Mu
user0721090601