问题 为什么将Perl 6命名参数约束为确定值使其成为必需值?


考虑这些子程序都采用一个命名参数。命名参数应该是可选的,我没有看到任何说法有例外。

没有类型限制,没有问题;命名参数不是必需的。使用可以接受类型对象的类型约束(没有注释, :U,和 :_) 没有问题。

Parameter '$quux' of routine 'quux' must be an object instance of type 'Int', 
not a type object of type 'Int'.  Did you forget a '.new'?
  in sub quux at /Users/brian/Desktop/type.p6 line 16
  in block <unit> at /Users/brian/Desktop/type.p6 line 37

使用需要定义值的类型约束(使用。注释) :D)命名参数不再是可选的。也就是说,对于任何其他定义,我不必提供值。有了 :D 我必须提供一个价值。我宁愿不遗漏 :D 因为我想要的价值必须定义。

来自 签名 文档:

通常,类型约束仅检查传递的值是否为正确类型。

但是,我没有传递任何价值。我认为这些约束只对作业有关。因为我没有明确地提供一个值来分配我期望没有任务,没有问题。 Rakudo 2017.10的情况并非如此。这导致我以各种令人讨厌的方式解决这个问题。这与我的问题有关 Perl 6块是一个参数还是无参数? 我试图区分零和一个参数的情况。

我可以通过分配默认值来解决这个问题,但在某些情况下,没有默认值是有意义的。一个 Bool 很简单,例如,但是确定的是什么 Int 适合吗?无论它是什么,都会有一些神奇的价值,会使代码变得复杂和分散注意力。我这样做了 Perl 6是否具有Infinite Int 但我逃避​​了,因为 Inf 在这种情况下,它可以作为有效值。

sub foo ( :$foo ) {
    put $foo.defined ?? 'foo defined' !! 'foo not defined';
    }

sub bar ( Int :$bar ) {
    put $bar.defined ?? 'bar defined' !! 'bar not defined';
    }

sub baz ( Int:U :$baz ) {
    put $baz.defined ?? 'baz defined' !! 'baz not defined';
    }

sub quux ( Int:D :$quux ) {
    put $quux.defined ?? 'quux defined' !! 'quux not defined';
    }

sub quack ( Int:_ :$quack ) {
    put $quack.defined ?? 'quack defined' !! 'quack not defined';
    }

foo();
foo( foo => 2 );

bar();
bar( bar => 2 );

baz();
baz( baz => Int );

quack();
quack( quack => 2 );

quux( quux => 2 );
quux();

10374
2018-01-09 10:40


起源



答案:


所有参数总是有一些值,即使它们是可选的。我澄清了你参考的文档 379678 和 b794a7

可选参数具有默认默认值,它们是显式或隐式类型约束的类型对象(隐式约束为 Any 对于例程和 Mu 对于块)。

sub (Int $a?, Num :$b) { say "\$a is ", $a; say "\$b is ", $b }()
# OUTPUT:
# $a is (Int)
# $b is (Num)

在上面,默认默认值传递参数的类型约束。如果你使用的是同样的情况 :U 要么 :_ 类型表情。

但是,当你使用的时候 :D 键入smiley,默认默认值不再与类型约束匹配。如果不加以检查,你将失去指定的好处 :D 约束。例如,默认的默认类型对象会导致此例程的主体爆炸,这需要参数为明确的值。

sub (Int:D $a?, Num:D :$b) { say $a/$b }()

并回答关于是否指定的名义问题 :D 应该自动生成参数。我是-1的想法,因为它引入了一个特殊情况,用户将不得不学习只保存单个字符的输入( !根据需要标记param)。这样做也会产生一个不太有用的错误,它会讨论arity或required参数,而不是实际问题:参数的类型检查失败的参数的默认默认值。


8
2018-01-09 13:19





FWIW,可选位置参数存在类似问题:

sub a(Int:D $number?) { ... }
a; # Parameter '$number' of routine 'a' must be an object instance of type 'Int', not a type object of type 'Int'.  Did you forget a '.new'

如果将类型对象指定为默认值,则会出现同样的问题:

sub a(Int:D $number = Int) { ... };
a; #  # Parameter '$number' of routine 'a' must be an object instance of type 'Int', not a type object of type 'Int'.  Did you forget a '.new'

我担心这只是后果的结果 :D 应用于参数时的约束:您只需指定一个已定义的默认值,即可在不使用任何参数的情况下调用它。

另一种方法当然可以是使用a multi sub 并且需要命名参数:

multi sub a() { say "no foo named" }
multi sub a(Int:D :$foo!) { say "foo is an Int:D" }

希望这可以帮助


4
2018-01-09 12:35



表达每个参数组合的多个子组件是难以处理的。 - brian d foy
我认为文档不应该说“可选参数”,而应该说“隐式设置参数”或类似的东西,以强调参数将存在,而这仅仅是谁设置值的问题。 - brian d foy
“可选参数”中的“可选”并不意味着该参数是可选的。相反,它意味着 传递一个论点 对应于该参数是可选的。 - raiph
这就是你不应该说“可选参数”的原因。请记住,那些不知道其中任何内容的人会读到这一点,并认为文档意味着他们所说的。 - brian d foy
没办法(imo)。 “可选参数”意味着它所说的,你只是错误地解释了“foo参数”的意思,然后认为它是明显的,唯一合理的解释。可选参数是可选参数,就像读写参数是读写参数一样。参数本身始终是不可变对象,是不可变签名的一部分。但是“读写参数”必须绑定到读写 论据。英语在这种情况下是变幻无常的,但声称“读写参数”从根本上说是错误的,并不意味着它所说的太过分了。伊莫。 - raiph


答案:


所有参数总是有一些值,即使它们是可选的。我澄清了你参考的文档 379678 和 b794a7

可选参数具有默认默认值,它们是显式或隐式类型约束的类型对象(隐式约束为 Any 对于例程和 Mu 对于块)。

sub (Int $a?, Num :$b) { say "\$a is ", $a; say "\$b is ", $b }()
# OUTPUT:
# $a is (Int)
# $b is (Num)

在上面,默认默认值传递参数的类型约束。如果你使用的是同样的情况 :U 要么 :_ 类型表情。

但是,当你使用的时候 :D 键入smiley,默认默认值不再与类型约束匹配。如果不加以检查,你将失去指定的好处 :D 约束。例如,默认的默认类型对象会导致此例程的主体爆炸,这需要参数为明确的值。

sub (Int:D $a?, Num:D :$b) { say $a/$b }()

并回答关于是否指定的名义问题 :D 应该自动生成参数。我是-1的想法,因为它引入了一个特殊情况,用户将不得不学习只保存单个字符的输入( !根据需要标记param)。这样做也会产生一个不太有用的错误,它会讨论arity或required参数,而不是实际问题:参数的类型检查失败的参数的默认默认值。


8
2018-01-09 13:19





FWIW,可选位置参数存在类似问题:

sub a(Int:D $number?) { ... }
a; # Parameter '$number' of routine 'a' must be an object instance of type 'Int', not a type object of type 'Int'.  Did you forget a '.new'

如果将类型对象指定为默认值,则会出现同样的问题:

sub a(Int:D $number = Int) { ... };
a; #  # Parameter '$number' of routine 'a' must be an object instance of type 'Int', not a type object of type 'Int'.  Did you forget a '.new'

我担心这只是后果的结果 :D 应用于参数时的约束:您只需指定一个已定义的默认值,即可在不使用任何参数的情况下调用它。

另一种方法当然可以是使用a multi sub 并且需要命名参数:

multi sub a() { say "no foo named" }
multi sub a(Int:D :$foo!) { say "foo is an Int:D" }

希望这可以帮助


4
2018-01-09 12:35



表达每个参数组合的多个子组件是难以处理的。 - brian d foy
我认为文档不应该说“可选参数”,而应该说“隐式设置参数”或类似的东西,以强调参数将存在,而这仅仅是谁设置值的问题。 - brian d foy
“可选参数”中的“可选”并不意味着该参数是可选的。相反,它意味着 传递一个论点 对应于该参数是可选的。 - raiph
这就是你不应该说“可选参数”的原因。请记住,那些不知道其中任何内容的人会读到这一点,并认为文档意味着他们所说的。 - brian d foy
没办法(imo)。 “可选参数”意味着它所说的,你只是错误地解释了“foo参数”的意思,然后认为它是明显的,唯一合理的解释。可选参数是可选参数,就像读写参数是读写参数一样。参数本身始终是不可变对象,是不可变签名的一部分。但是“读写参数”必须绑定到读写 论据。英语在这种情况下是变幻无常的,但声称“读写参数”从根本上说是错误的,并不意味着它所说的太过分了。伊莫。 - raiph


我通过检查确切的类型来解决这个问题 Any 或智能匹配我真正想要的那个:

sub f ( :$f where { $^a.^name eq 'Any' or $^a ~~ Int:D } ) {
    put $f.defined ?? "f defined ($f)" !! 'f not defined';
    }

f( f => 5 );
f();

要回答我原来的问题:所有参数都是必需的。这只是他们如何获得价值的问题。它可以通过参数,显式默认值或隐式默认值(基于其类型约束)。


1
2018-01-10 01:44



考虑到在这个特定的SOQA中明显的思考过程,我认为我得到了为什么你写了“所有参数都是必需的”,但它直接与P6语言及其文档中长期合理的现有用法相矛盾(例如 .optional)其中位置和命名参数都是可选的或必需的。 - raiph
这些定义适用于用户指定的方式 参数,但正如我所表明的,它与其他期望的冲突产生了冲突 参数。 - brian d foy
我认为补丁更糟糕了。我认为这是心理模型中一个更大的问题。 - brian d foy
FWIW,你在那里做两个智能匹配(一个在块中显式,另一个在其结果中 where)。你可以通过使用thunk来使它快〜15%: (:$f where .WHAT =:= Any || Int:D)  以来 where 条款阻止调度缓存,无论如何你都在检查身体中的.definedness,你可以得到〜7.8倍更快的代码 Int 类型约束和 .DEFINITE 检查身体
>“我认为补丁使情况变得更糟。”请打开一个doc Issue,这样可以改进: github.com/perl6/doc/issues/new