Como criar uma captura dinamicamente (Raku)

8

No exemplo a seguir, tento criar um Capture dinamicamente "convertendo" uma matriz (@a) em um Capture.

Considere o 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);

O resultado é:

  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 : 

A primeira execução (com o Capture $ c1) está sendo executada como deveria, produzindo o comportamento desejado. A segunda e terceira tentativas, para criar uma Captura dinamicamente, estão falhando (provavelmente porque o argumento da sub-rotina f nesses casos NÃO é a Captura desejada). Observo que os pares incorporados na matriz @a são considerados membros de uma lista e NÃO nomeados parâmetros como eu queria que fossem.

Eu sei que deve haver, de certa forma, um "achatamento" dos pares da matriz, antes de passar para a sub-rotina f, mas NÃO consigo descobrir o caminho para fazer isso!

Alguém pode me dar uma dica?

jakar
fonte

Respostas:

7

Na classe, Listhá o método Capture, que funciona exatamente como você deseja:

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();
}

Você pode modificar a definição da função fpara trabalhar diretamente com a 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)é o chamado tipo de coerção . Ele aceita, Anymas coage Capture, ou seja, (repetidamente) chama o método Capturepara obtê-lo.

Além disso, Capturevocê pode usar a correspondência de padrões. Assim, a última definição da função fpode ser alterada para:

sub f ( (**@list, *%hash) ) {
#or even sub f ( (*@list, :t1($t),*%hash) ) {
    say() ;
    say '  List : ', @list;
    # say ' test1 : ', $t;
    say '  Hash : ', %hash;
    say();
}  
wamba
fonte
Você pode explicar um pouco mais por que sua segunda solução funciona?
jakar 3/01
1
Eu adicionei explicações no final da minha resposta.
wamba 03/01
Se você estiver usando Foo(Any)como um tipo, provavelmente poderá usar Foo(). Não consigo imaginar um momento em que você daria uma Anymas não umaAny Mu
user0721090601