Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a Capture dynamically (Raku)

In the following example I try to create a Capture dynamically by "converting" an array (@a) to a Capture.

Consider the code:

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

The result is:

  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 : 

The first run (with Capture $c1) is running as it should, producing the desired behaviour. The second and third attempts, to create a Capture dynamically, are failing (probably because the argument of the subroutine f in those cases is NOT the desired Capture). I observe that the pairs incorporated into array @a, are taken to be members of a list and NOT named parameters as I wanted them to be.

I know that there must be, sort of speak, a "flattening" of the pairs in the array going on, before passing to subroutine f, but i can NOT figure out the way to do that!

Can anyone give me a hint?

like image 331
jakar Avatar asked Jan 03 '20 14:01

jakar


1 Answers

In the class List there is the method Capture, which works exactly how you want:

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

You could modify the definition of the function f to work directly with the list @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) is so-called coercion type. It accepts Any but coerces Capture, i.e. it (repeatedly) calls method Capture to get it.

In addition, by Capture you can use pattern matching. Thus last definition of the function f could be changed to:

sub f ( (**@list, *%hash) ) {
#or even sub f ( (*@list, :t1($t),*%hash) ) {
    say() ;
    say '  List : ', @list;
    # say ' test1 : ', $t;
    say '  Hash : ', %hash;
    say();
}  
like image 58
wamba Avatar answered Nov 08 '22 22:11

wamba