首页 文章

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

提问于
浏览
5

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

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

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

签名实际上是 ;; $_? is raw . 这是一个可选参数 . 由于没有显式签名,因此未在块中定义 @_ 变量 .

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

&block();  # no argument

但是还有一个论点情况, $_ 将是未定义的 . 类型对象始终未定义:

&block(Int);

但是,其中没有任何东西的 $_ 实际上是Any(而不是,例如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参数和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

3 回答

  • 2

    据我所知,知道在没有显式签名的情况下传递的参数数量的唯一方法是在体内使用 @_ ,这将生成一个 :(*@_) 签名 .

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

    是的,好的老 @_ 仍在那里,如果你想要它:-)

  • 1
    { 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';
        }
    }
    
  • 3

    这就是我解决这个问题的方法 . 我希望以更清洁的方式做到这一点,但语言的聪明性妨碍了我必须解决它 . 这适用于位置参数,但有更深层次的shenanigans用于命名参数,我不会在这里处理 .

    我有另一个问题,Why does constraining a Perl 6 named parameter to a definite value make it a required value?,答案澄清说实际上没有可选参数 . 只有参数具有默认值,并且如果我没有明确指定一个参数,则存在隐式默认值 .

    我的问题的症结在于,我想知道何时给出参数值,如果没有指定类型,我什么时候才知道't. I give it a value through an argument or an explicit default. An implicit default is a type object of the right type. That' s Any . 隐式默认值必须满足我指定的任何约束 .

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

    第二个目标是轻松区分代码中的特殊情况 . 我希望减少深层代码中某些部分需要知道的特殊知识量 .

    我可以通过显式指定一个特殊值来获得第三种情况(我知道没有参数或合适的默认值),我知道这个值可能比 Any 更无意义 . 那是 Mu . 它是所有未定义值中最未定义的值 . AnyMu 的两个子类型之一(另一个是 Junction )但是你几乎从不会在普通代码中的某个值中看到 Mu 结束 . 用户代码中未定义的内容从 Any 开始 .

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

    因为我正在使用 Mu ,所以有一些我不能做的事情,比如使用 === 运算符 . 智能匹配赢得了't work because I don' t想要测试继承链 . 我可以直接检查对象名称:

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

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

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

相关问题