如何动态创建捕获(Raku)

huangapple go评论57阅读模式
英文:

How to create a Capture dynamically (Raku)

问题

在以下示例中,我尝试通过将数组(@a)“转换”为一个Capture来动态创建一个Capture。

考虑以下代码:

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

结果是:

  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 : 

第一次运行(使用Capture $c1)运行正常,产生了期望的行为。第二次和第三次尝试动态创建Capture失败(可能是因为在这些情况下子例程f的参数不是所需的Capture)。我观察到,包含在数组@a中的键值对被视为列表的成员,而不是我想要的命名参数。

我知道在传递给子例程f之前,数组中的键值对必须进行某种程度的“扁平化”,但我无法弄清楚如何做到这一点!有人能给我一些提示吗?

英文:

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?

答案1

得分: 7

List类中有一个方法Capture,它的工作方式与您想要的完全相同:

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

您可以修改函数f的定义,以直接使用列表@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) 是所谓的强制类型转换。它接受 Any 但将其强制转换为 Capture,即(重复地)调用方法 Capture 来获取它。

此外,通过使用 Capture,您可以使用模式匹配。因此,函数 f 的最后一个定义可以更改为:

sub f ( (**@list, *%hash) ) {
#或者甚至 sub f ( (*@list, :t1($t),*%hash) ) {
    say() ;
    say '  List : ', @list;
    # say ' test1 : ', $t;
    say '  Hash : ', %hash;
    say();
}  
英文:

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

huangapple
  • 本文由 发表于 2020年1月3日 22:38:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/59580454.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定