Perl 6 块是一个参数还是 none?

Is that one argument or none for a Perl 6 block?

在没有显式签名的块中,Perl 6 区分有参数和无参数的方法是什么?我对此没有任何实际用途,但我很好奇。

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

my &block := { put "The argument was $_" };

签名其实是;; $_? is raw。这是一个可选参数。 @_ 变量未在块中定义,因为没有显式签名。

没有参数,其中 $_ 将是未定义的:

&block();  # no argument

但也有一种单参数情况,其中 $_ 将是未定义的。类型对象始终未定义:

&block(Int);

但是,一个没有任何内容的 $_ 实际上是一个 Any (rather than, say, Nil)。我分不清这两种情况的区别:

&block();
&block(Any);

这里有一个更长的例子:

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

注意无参数和任何参数形式显示相同的东西:

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
{ put $_.perl }

有点类似于:(不起作用)

-> ;; $_? is raw = CALLERS::<$_> { put $_.perl }

由于块外 $_ 的默认 is defaultAny,如果您在调用函数之前不将任何内容放入 $_ 中,您会得到Any.


要获得完全相似的东西,您可以区分它们,请使用 Capture :

my &foo = -> ;; |C ($_? is raw) {
    unless C.elems {
       # pretend it was defined like the first Block above
       CALLER::<$_> := CALLER::CALLERS::<$_>
    }
    my $called-with-arguments := C.elems.Bool;


    if $called-with-arguments {
        say 'called with arguments';
    } else {
        say 'not called with arguments';
    }
}

据我所知,要知道没有显式签名传递的参数的 数量 的唯一方法是在正文中使用 @_,这将生成一个:(*@_)签名。

my &block := { say "Got @_.elems() parameter(s)" };
block;               # Got 0 parameter(s)
block 42;            # Got 1 parameter(s)
dd block.signature;  # :(*@_)

是啊,老@_还在那里,如果你想要的话:-)

这是我解决这个问题的方法。我很想以一种更简洁的方式来做这件事,但是语言的聪明之处妨碍了我,我必须解决它。这适用于位置参数,但命名参数有更深层次的恶作剧,我不会在这里处理这些。

我有另一个问题,,其中的答案澄清实际上没有可选参数。只有参数具有默认值,如果我不显式分配参数,则存在隐式默认值。

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

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

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

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

开始

我可以创建一个约束来检查我想要的类型或 Mu 并设置默认值 Mu。如果我看到 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);

现在大多数调用都失败了,因为它们没有指定正确的东西。

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