我正在尝试解决这个问题,这实际上是由另一个与callwithand 的不同行为相关的stackoverflow问题引发的samewith.后者似乎有明确的定义,然而,它并不是那么清楚callwith.
看看这个例子:
proto how-many(|) {*}
multi sub how-many( Pair $a, Pair $b ) {
say "Int $a and $b";
return "There are $a and $b"
}
multi sub how-many( $a, $b ) {
say "Not int $a and $b";
my $calling = callwith( 1 => $a, 2 => $b );
return $calling;
}
say how-many( "little piggie","littler piggie" );
Run Code Online (Sandbox Code Playgroud)
根据文档,callwith应该调用下一个匹配的候选人.但是,这是输出:
Not int little piggie and littler piggie
(Any)
Run Code Online (Sandbox Code Playgroud)
所以它调用第二个版本how-many,然后调用一个不存在的函数(显然)并返回Nil,它被传递Any给调用例程.
我也试过使用不同的签名,但这也不起作用.文档中的示例显然表明只有当变量属于同一个类层次结构时它才会起作用.是这样的吗?它可能不是,因为改变位置签名Any $a, Any $b也不起作用,既不改变声明的顺序.
以上,改变
callwith与samewith将明显的工作,但我想了解callwith作品,而不是使上述工作的代码.
此外,它似乎是想下来的类层次结构,但不起来.这个例子在烤,Perl 6测试套件中,有效:
my $tracker = '';
multi d($x) { $tracker ~= 'Any' ~ $x };
multi d(Int $x) { $tracker ~= 'Int'; callwith($x+1); $tracker ~= 'Int' };
lives-ok { d(3) }, 'can call callwith inside a multi sub';
Run Code Online (Sandbox Code Playgroud)
但是,如果我们更改它,以便我们callwith从层次结构的底部使用,如下所示:
my $tracker = '';
multi d($x) { $tracker ~= 'Any' ~ callwith( "called-with" => $x) };
multi d(Pair $x) { $tracker ~= "Pair $x" };
say d( 3 );
Run Code Online (Sandbox Code Playgroud)
它失败了
Use of Nil in string context in sub d at rewrite-test-callwith.p6 line 6
Run Code Online (Sandbox Code Playgroud)
这是预期的行为吗?
所有的callwith,nextwith,callsame,并nextsame通过一组候选人的行走由原始参数确定.因此,虽然callwith可以用来替换一个参数,但这就是它所做的一切.它不会导致预先确定的候选列表的变化进行迭代.
考虑这三个候选人:
multi foo(Any $x) { say "In Any case with $x" }
multi foo(Real $x) { say "In Real case with $x"; callwith($x.Int); }
multi foo(Int $x) { say "In Int case with $x"; callsame(); }
Run Code Online (Sandbox Code Playgroud)
我们可以询问哪些候选人申请.cando并通过了Capture.从而:
.say for &foo.cando(\(42));
Run Code Online (Sandbox Code Playgroud)
将产生以下输出:
sub foo (Int $x) { #`(Sub|78402328) ... }
sub foo (Real $x) { #`(Sub|78412816) ... }
sub foo ($x) { #`(Sub|78412968) ... }
Run Code Online (Sandbox Code Playgroud)
由于所有3名候选人都匹配 调用foo(42)将导致以下输出:
In Int case with 42
In Real case with 42
In Any case with 42
Run Code Online (Sandbox Code Playgroud)
相比之下,有:
.say for &foo.cando(\(4.2));
Run Code Online (Sandbox Code Playgroud)
输出是:
sub foo (Real $x) { #`(Sub|78412816) ... }
sub foo ($x) { #`(Sub|78412968) ... }
Run Code Online (Sandbox Code Playgroud)
并呼吁foo(4.2)有callwith通过这些候选人迭代:
In Real case with 4.2
In Any case with 4
Run Code Online (Sandbox Code Playgroud)
callwith最普通的候选人中的一个或类似的人将不会有任何影响,并将评估为Nil.
虽然这里的示例是多子,但是同样适用于包装器和非多方法,它们也走在预定的列表中.
最后,还值得观察的是,如果每次都有一个新的调度,我给出的例子将最终作为无限递归.通过走预定的候选列表,这种情况永远不会发生.
请注意,这些都不适用samewith,这恰好存在于完全新的调度中.