对于Perl 6块,这是一个参数还是没有?

bri*_*foy 6 arguments subroutine perl6

什么是Perl 6方法来区分没有显式签名的块中的参数和无参数之间的区别?我没有任何实际用途,但我很好奇.

没有显式签名的块将值放入$_:

my &block := { put "The argument was $_" };
Run Code Online (Sandbox Code Playgroud)

签名实际上是;; $_? is raw.这是一个可选参数.该@_变量不是在块定义的,因为没有明确的签名.

没有参数,$_未定义的地方:

&block();  # no argument
Run Code Online (Sandbox Code Playgroud)

但是也存在一个$_未定义的论证情况.类型对象始终未定义:

&block(Int);
Run Code Online (Sandbox Code Playgroud)

但是,$_其中没有任何东西实际上是一个Any(而不是说,Nil).我无法区分这两种情况:

&block();
&block(Any);
Run Code Online (Sandbox Code Playgroud)

这是一个较长的例子:

my $block := {
    say "\t.perl is {$_.perl}";

    if $_ ~~ Nil {
        put "\tArgument is Nil"
        }
    elsif ! .defined and $_.^name eq 'Any' {
        put "\tArgument is an Any type object"
        }
    elsif $_ ~~ Any {
        put "\tArgument is {$_.^name} type object"
        }
    else {
        put "\tArgument is $_";
        }
    };

put "No argument: ";    $block();
put "Empty argument: "; $block(Empty);
put "Nil argument: ";   $block(Nil);
put "Any argument: ";   $block(Any);
put "Int argument: ";   $block(Int);
Run Code Online (Sandbox Code Playgroud)

注意no参数和Any参数表单显示相同的东西:

No argument:
    .perl is Any
    Argument is an Any type object
Empty argument:
    .perl is Empty
    Argument is Slip type object
Nil argument:
    .perl is Nil
    Argument is Nil
Any argument:
    .perl is Any
    Argument is an Any type object
Int argument:
    .perl is Int
    Argument is Int type object
Run Code Online (Sandbox Code Playgroud)

bri*_*foy 1

这是我解决这个问题的方法。我很想以一种更干净的方式做到这一点,但语言的巧妙性阻碍了我,我必须解决它。这适用于位置参数,但命名参数还有更深层次的诡计,我不会在这里处理这些。

我还有另一个问题,为什么将 Perl 6 命名参数限制为确定值会使其成为必需值?,其中答案澄清了实际上没有可选参数。只有一些参数具有默认值,并且如果我没有显式分配默认值,则存在隐式默认值。

我的问题的关键是我想知道什么时候给了参数一个值,什么时候没有给参数一个值。我通过参数或显式默认值给它一个值。隐式默认值是正确类型的类型对象。Any如果我没有指定类型的话。该隐式默认值必须满足我指定的任何约束。

第一个目标是严格限制用户在调用代码时可以提供的值。如果未定义的值无效,则不应允许他们指定一个值。

第二个目标是轻松区分代码中的特殊情况。我想减少更深层次代码的某些部分需要了解的特殊知识的数量。

我可以通过显式分配一个我知道不能是任何其他有意义的东西的特殊值来获得第三种情况(我知道没有参数或合适的默认值)。有一个值比 更没有意义Any。那是Mu。它是所有未定义值中最未定义的值。是Any的两个子类型之一Mu(另一个是Junction),但您几乎永远不会Mu在正常代码中看到您的值之一的结尾。用户代码中未定义的内容从 开始Any

我可以创建一个约束来检查我想要的类型或Mu设置默认值Mu. 如果我看到 a,Mu我就知道没有争论,这是Mu因为我的约束设置了这一点。

由于我正在使用,Mu所以有些事情我不能做,比如使用===运算符。智能匹配不起作用,因为我不想测试继承链。我可以直接检查对象名称:

my $block := ->
    $i where { $^a.^name eq 'Mu' or $^a ~~ Int:D } = Mu
    {
    say "\t.perl is {$i.perl}";

    put do given $i {
        when .^name eq 'Mu'  { "\tThere was no argument" }
        when Nil             { "\tArgument is Nil"       }
        when (! .defined and .^name eq 'Any') {
            "\tArgument is an Any type object"
            }
        when .defined {
            "\tArgument is defined {.^name}"
            }
        default { "\tArgument is {.^name}" }
        }
    };

put "No argument: ";         $block();
put "Empty argument: ";      try $block(Empty); # fails
put "Nil argument: ";        try $block(Nil);   # fails
put "Any type argument: ";   try $block(Any);   # fails
put "Int type argument: ";   try $block(Int);   # fails
put "Int type argument: ";   $block(5);
Run Code Online (Sandbox Code Playgroud)

现在,大多数调用都会失败,因为它们没有指定正确的内容。

如果这些是例程,我可以为少数情况制作多重,但最终这是一个更糟糕的解决方案。如果我有两个参数,我需要四个多重参数。有了三个这样的参数,我就需要六个。这是很多样板代码。但是,块不是例程,所以这里没有实际意义。