Perl 6 签名中的匿名参数是否会丢弃该值?

Does an anonymous parameter in a Perl 6 signature discard the value?

在 Perl 6 Signature docs 中,有一个匿名 slurpy 参数的例子:

sub one-arg (@)  { }
sub slurpy  (*@) { }
one-arg (5, 6, 7); # ok, same as one-arg((5, 6, 7))
slurpy  (5, 6, 7); # ok
slurpy   5, 6, 7 ; # ok

子例程中没有语句,主要是因为围绕它的文本是关于满足签名的参数列表,而不是子例程用它做什么。

我正在玩它并尝试制作一个子例程,该子例程采用多个项目之一的列表(因此,不是零项目)。我并没有特别在意给他们起名字。我认为即使有签名,我仍然可以访问 @_ 中的参数列表。但是,当您没有签名时,您会得到 @_

$ perl6
To exit type 'exit' or '^D'
> sub slurpy(*@) { say @_ }
===SORRY!=== Error while compiling:
Placeholder variable '@_' cannot override existing signature
------> sub⏏ slurpy(*@) { say @_ }

是否有其他方法获取参数列表,或者匿名参数是否丢弃它们?我看到它们在有关类型约束的部分中使用,但没有使用任何参数值的示例。我还能得到参数列表吗?

要填充 @_,签名必须是隐式的或显式的,不能两者兼而有之。

sub implicit             {      say @_ } # most like Perl 5's behaviour
sub explicit     ( *@_ ) {      say @_ }
sub placeholder          { $^a; say @_ }

这也适用于方块

my &implicit    =        {      say @_ }
my &explicit    = -> *@_ {      say @_ }
my &placeholder =        { $^a, say @_ }

块也可以有一个隐式参数 $_,但如果有 @_ 则优先。

{     say $_ }(5) # 5
$_ = 4;
{ @_; say $_ }(5) # 4

这样做是有意义的,因为一个程序员可能认为它按照您认为的方式工作,或者它像隐式的那样笨拙,而另一个程序员可能认为它获得了所有剩余的参数.

sub identical (     @_           ) { say @_ }
sub slurpy    (    *@_ ( @, *@ ) ) { say @_ } # same as implicit
sub slurpy2   (   **@_ ( @, *@ ) ) { say @_ } # non-flattening
sub remaining ( @, *@_           ) { say @_ }

identical  [1,2];       # [1 2]
slurpy    $[1,2],3,4,5; # [[1 2] 3 4 5]
slurpy2    [1,2],3,4,5; # [[1 2] 3 4 5]
remaining  [1,2],3,4,5; # [3 4 5]

@_ 也可能会被添加为错误,在这种情况下最好产生错误。


如果不声明捕获参数,就无法获取原始参数。

sub raw-one    ( |capture ( @ ) ) { capture.perl }
sub raw-slurpy ( |capture, *@   ) { capture.perl }

raw-one    [1,2]; # \([1, 2])
raw-slurpy  1,2 ; # \(1, 2)

Does an anonymous parameter in a Perl 6 signature discard the value?

是的,除非您使用函数签名中的某个命名参数捕获参数,否则它在函数体中不可用。 (PS:不过,正如莫里茨的回答所示,它们并没有真正被丢弃。)

I figured I'd still have access to the argument list in @_ even with the signature.

@_ 不是使用参数的替代方法 - 它 一个参数。

每个函数都有一个明确定义的签名来指定其参数,它们代表了函数体获取函数传递值的唯一机制。

只是函数签名的声明方式有3种不同:

  1. 如果您明确写出一个签名,那就是使用的签名。
  2. 如果您在函数体中使用 占位符参数@_$^foo 等),编译器会使用该信息来构建给你的签名:
    say { $^a + @_ }.signature;  # ($a, *@_)
  3. 如果以上都不是,则签名变为:
    • 在子程序的情况下,接受零参数的子程序:
      say (sub { 42 }).signature; # ()
    • 在裸块的情况下,接受零个或一个可用参数的块 $_
      say { 42 }.signature;  # (;; $_? is raw)

在所有情况下,函数在编译时都以明确的签名结束。 (尝试在已经具有显式签名的函数中使用 $^foo 是编译时错误。)

Is there another way to get the argument list

确保使用非匿名参数捕获它。如果您希望它可以作为 @_ 访问,则在您正在编写的显式签名中调用它。

I was [...] trying to make a subroutine that takes a list of one of more items

您可以为此使用子签名:

sub foo (*@_ [$, *@]) { ... };

或者 where 约束:

sub foo (*@_ where .so) { ... };

这些值没有被丢弃;例如,您可以通过 nextsame:

访问它
multi access-anon(*@) is default {
    say "in first candidate";
    nextsame;
}
multi access-anon(*@a) {
    @a;
}
say access-anon('foo')

输出:

in first candidate
[foo]

但要获得原始 objective(至少包含一个元素的数组),您实际上并不需要访问该列表;您可以使用子签名:

sub at-least-one(@ [$, *@]) { }
at-least-one([1]);   # no error
at-least-one([]);    # Too few positionals passed; expected at least 1 argument but got only 0 in sub-signature