如何在Perl 6中将序列作为参数传递?

bri*_*foy 8 perl6 seq

在Perl 6中,我可以迭代一个文字序列:

.say for 0 ... 3;
Run Code Online (Sandbox Code Playgroud)

我可以绑定到标量并迭代:

my $s := 0 ... 3;
.say for $s;
Run Code Online (Sandbox Code Playgroud)

但我无法绑定到标量,将其作为参数传递,然后迭代:

my $t := 0 ... 3;
show( $t );

sub show ( $seq ) { .say for $seq }
Run Code Online (Sandbox Code Playgroud)

子例程获取Seq类型的单个元素,但它不会迭代它.

0
1
2
3
0
1
2
3
(0 1 2 3)
Run Code Online (Sandbox Code Playgroud)

在准备参数的过程中有什么东西已遍历所有内容吗?

rai*_*iph 11

标量容器中保存的值不会自动迭代

虽然两者$s$seq标量(又名"变量"),$s而您直接绑定到一个序列值$seq绑定到一个中介标量(注意大写S)"容器",里面包含的序列.当与诸如此类的功能一起使用时,标量容器中保存的值不会自动迭代for.


更详细:

my $s := 0 ... 3;
.say for $s;
Run Code Online (Sandbox Code Playgroud)

因为my变量声明使用直接绑定运算符:=进行初始化,$s所以直接绑定到单个Seq值0 ... 3.

这意味着for语句看到一个Seq值,确定它执行Iterable角色,并展平(迭代)它.

现在考虑一下:

my $s := 0 ... 3;
my $container = $s;
.say for $container;
Run Code Online (Sandbox Code Playgroud)

因为第二个my声明使用赋值运算符=进行初始化,所以新变量$container首先绑定到一个新的Scalar容器,然后"包含"所分配的任何内容.

为了与语言范围内的Slurpy Conventions保持一致(特别是:"Scalar容器中的Iterable不计算"),for语句不会迭代Scalar容器中保存的值,因此该.say for $container行只执行一个say.

类似的情况也适用于您的原始show例程,因为默认情况下,变量参数声明是(语义上)容器.

一种选择是is raw$seq参数中添加特征:

sub show ( $seq is raw ) { .say for $seq }
Run Code Online (Sandbox Code Playgroud)

这可以防止通常自动绑定$seq到标量容器(反过来将包含Seq值)作为调用的一部分show.

另一个选择是让$seq绑定到Scalar容器,但使用前缀$seqshow例程的主体中显式地展平(迭代)变量|:

sub show ( $seq ) { .say for |$seq }
Run Code Online (Sandbox Code Playgroud)


sml*_*mls 7

除了is rawraiph建议的参数特性,您还可以使用无sigil的变量作为参数,它不会引入Scalar容器:

sub show (\seq) { .say for seq }
Run Code Online (Sandbox Code Playgroud)

(您也可以将此表单用于普通变量,例如my \a = 5; say a;,但请注意它们仅是单一赋值.)

这种+形式的变体是形式,如果它是一个Iterable(如a ListSeq),则传递raw参数,但是当传递一个非可迭代的参数时,它将它提升List为一个元素的一个,这样函数体可以总是得到一个Iterable:

sub show (+seq) { .say for seq }
Run Code Online (Sandbox Code Playgroud)

(这是大多数内置列表处理例程所喜欢grepzip使用的.)

当然,如果你更喜欢使用$引入Scalar容器的参数,你可以通过调用.list它上面的方法在迭代它之前再次"去包容" 它:

sub show ($seq) { .say for $seq.list }  # explicit

sub show ($seq) { .say for @$seq }      # short-hand syntax
Run Code Online (Sandbox Code Playgroud)

(更新:呃,.list实际上变成了Seq一个List,即在大的情况下它不会有内存效率Seq.使用|$seq就像你在自己的答案中已经发现的那样,没有这个问题.)