`ispure`特性和默认参数

下面的 &greet 函数是纯的,可以适当地标上is pure trait。

sub greet(Str:D $name) { say "Hello, $name" }
my $user = get-from-db('USER');
greet($user);

然而,这不是:

sub greet { 
    my $name = get-from-db('USER');
    say "Hello, $name" 
}

greet($user);

不过这个呢?

sub greet(Str:D $name = get-from-db('USER')) { say "Hello, $name" }

greet();

从函数的“内部”来看,它看起来很纯粹——当参数绑定到相同的值时,它总是产生相同的输出,没有副作用。但是从函数的外部来看,它似乎是不纯的——当使用相同的参数调用两次时,它会产生不同的返回值。Raku/Rakudo 选择哪个前景?

回答

在实现参数的默认值时,语言可能至少采用两种策略:

  1. 将参数默认值视为编译器在遇到没有足够参数的调用时应在调用站点发出的内容,以便生成传递给被调用方的额外参数。这意味着可以支持参数的默认值,而无需在调用约定中对其进行任何明确支持。然而,这也要求您在编译时始终知道调用的去向(或者至少知道它足够准确以插入默认值,并且不能期望在子类的方法覆盖中使用不同的默认值并具有它解决了)。
  2. 有一个足够强大的调用约定,被调用者可以发现没有为参数传递值,然后计算默认值。

由于其动态特性,其中只有第二个对 Raku 真正有意义,这就是它所做的。

在执行策略 1 的语言中,将这样的函数标记为纯函数可以说是有意义的,因为计算每个调用点的默认寿命的代码,因此任何基于纯度的分析和可能的转换都必须处理评估默认值的代码,可以看到它不是纯值的来源。

在策略 2 和 Raku 下,我们应该将默认值理解为在其签名中具有默认值的块或例程的实现细节。因此,如果计算默认值的代码是不纯的,那么整个例程是不纯的,因此is puretrait 是不合适的。

更一般地,is pure如果对于给定的参数捕获,我们总是可以期望相同的返回值,则该特征适用。在给出的示例中,参数 capture()与此相矛盾。

这里的另一种分解是使用multisubs 而不是参数默认值,并且只用is pure.


回答

当您说 a sub 时is pure就保证任何给定的输入将始终产生相同的输出。在你的最后一个例子中sub greet,我认为你不能保证默认值的情况,因为数据库的内容可能会改变,或者get-from-db可能有副作用。

当然,如果你确定数据库没有变化,并且没有任何副作用,你仍然可以申请is puresub,但为什么要使用数据库呢?

你为什么要把一个子标记为is pure反正?好吧,它允许编译器在编译时对子例程的调用进行常量折叠。例如:

sub foo($a) is pure {
    2 * $a
}
say foo(21);   # 42

如果您查看为此生成的代码:

$ raku --target=optimize -e 'sub foo($a) is pure { 2 * $a }; say foo(21)'

那么你会在接近尾声时看到这个:

 ?   ?               - QAST::IVal(42) 

42是恒定折叠呼吁foo(21)。所以这样整个调用都被优化掉了,因为 sub 被标记is pure并且你提供的参数是一个常量。

  • I think my question wasn't clear enough. I understand that the relevant question is whether I can guarantee that "any given input will always produce the same output". But what I'm asking is what counts as "input". If the input is the _arguments_ that the caller passes in, then yes, the last &greet produces different output. But if the input is the _parameters_ that the function receives, then that &greet function always produces the same output for any given input. Typically, arguments are bound to parameters, so the distinction doesn't matter – but default arguments are an exception

以上是`ispure`特性和默认参数的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>