【发布时间】:2021-03-14 15:11:14
【问题描述】:
Raku docs say那个Code.assuming
返回一个 Callable,它实现与原始行为相同的行为,但传递给 .假设的值已经绑定到相应的参数。
使用.assuming 与将代码包装在匿名块(或子)中调用内部函数并绑定一些参数有什么区别?
例如,在下面的代码中,&surname-public(文档为.assuming 提供的示例)和&surname-block 之间有什么区别;
sub longer-names ( $first, $middle, $last, $suffix ) {
say "Name is $first $middle $last $suffix";
}
my &surname-public = &longer-names.assuming( *, *, 'Public', * );
my &surname-block = -> $a,$b,$c { longer-names($a, $b, 'Public', $c) }
surname-public( 'Joe', 'Q.', 'Jr.'); # OUTPUT: «Name is Joe Q. Public Jr.»
surname-block( 'Joe', 'Q.', 'Jr.'); # OUTPUT: «Name is Joe Q. Public Jr.»
我看到.assuming 节省了一些篇幅,并且在某些情况下可以更清晰一些。但我强烈怀疑我遗漏了其他一些差异。
【问题讨论】:
-
“节省一点长度”,“更清晰一点”。另外:❸静态编码意图。原则上
.assume有朝一日可能成为一个宏,它在编译时进行相关的优化,可靠地超过 JIT 可以做的事情。也许。 ❹ 保留原始签名。例如,如果更改了参数的名称或类型约束,则例程的柯里化版本将自动跟踪这些更改,这可能(通常是)对于参数类型/名称的编译器(Rakudo)强制执行而言是最好的和工具(例如 CommaIDE)显示签名。 -
@raiph 你很可能是正确的,这只是这 4 个差异。但是,我想知道…… Code.假设 source 大约有 275 行,这似乎需要花很多钱来减少到关闭。我还没有深入挖掘源头——尽管如果没有人知道答案,我会在有时间的时候挖掘——但这让我想知道它是否还有更多。
-
大概代码必须进行自定义的、完全手动的自省/元编程签名绑定的复制 和自定义的、完全手动的元编程构造一个新的签名,以及一个带有该签名的新闭包。绑定仿真需要遍历原始签名中的每个参数,注意哪些
.assuming参数已被传递,哪些被省略,哪些是*(也许还有**变体?)。构造也可能很冗长。而且我想错误消息可能是无数和/或复杂的构造,以便不是 LTA。 -
sub work($i, :$debug) { say $i if $debug; return $i }; my &w1 = &work.assuming(1); my &w2 = &w1.assuming(debug => True); w1(); w2();当您开始考虑可选的命名参数时,链接等柯里化与assuming相比变得相当冗长 -
"
.assuming的当前实现 - 用于对例程进行 curry 或其他主要参数 - 并不理想,利用新调度程序的参数重写功能的实现可能会执行好多了”(来自Towards a new general dispatch mechanism in MoarVM)