【问题标题】:How to apply one signature test to multiple positionals如何将一个签名测试应用于多个位置
【发布时间】:2021-12-29 22:31:06
【问题描述】:

我在 https://github.com/p6steve/raku-Physics-Measure 中编写了一些代码,用于在每个数学运算中查找 Measure 类型,并将工作交给非标准方法来调整 Unit 和 Error 方面并返回新值:

multi infix:<+> ( Measure:D $left, Real:D $right ) is export {
    my $result   = $left.clone;
    my $argument = $right;
    return $result.add-const( $argument );
}
multi infix:<+> ( Real:D $left, Measure:D $right ) is export {
    my $result   = $right.clone;
    my $argument = $left;
    return $result.add-const( $argument );
}
multi infix:<+> ( Measure:D $left, Measure:D $right ) is export {
    my ( $result, $argument ) = infix-prep( $left, $right );
    return $result.add( $argument );
}

这种模式对于 重复了 4 次,所以它相当于相当多的样板文件;我想减少一点。

那么,有没有更简洁的方法来将签名中的单个 Measure|Real 测试应用于两个位置,如果两者或一个但不匹配,则触发多重,并且为不妥协的人保留位置操作 ?

我不确定没有多重是最优雅的 - 也许只是将 Real-Measure 和 Measure-Real 压缩为一个?

【问题讨论】:

标签: raku measure units-of-measurement rakudo


【解决方案1】:

有几种方法可以解决这个问题,但我可能会做的——以及一个普遍有用的模式——是使用 subset 创建一个稍微过度包容的 multi 然后 redispatch 你应该的情况t 包括在内。对于您提供的示例,可能看起来有点像:

subset RealOrMeasure where Real | Measure;
multi infix:<+> ( RealOrMeasure:D $left, RealOrMeasure:D $right )  {
    given $left, $right {
       when Real,    Real    { nextsame }
       when Real,    Measure { $right.clone.add-const($left)  }
       when Measure, Real    {  $left.clone.add-const($right) }
       when Measure, Measure { my ($result, $argument) = infix-prep $left, $right;
                               $result.add($argument)}}

}

(注意:我没有用Measure测试过这段代码;如果它不起作用,请告诉我。但总体思路应该是可行的。)

【讨论】:

  • subset RealOrMeasure where * ~~ Real | Measure; subset RealOrMeasure where Real | Measure; 不工作吗?
  • @codesections / @raiph -- 是的,这正是我的想法,谢谢!这引发的一件事是,如果有一种方法可以一次性检查所有位置,例如( ($left, $right).all ~~ RealOrMeasure:D )
  • 请注意,子集类型是决胜局,因此使用这种方法会影响候选者的排序方式,这可能会导致意外。
  • (等到??...2022 年快乐!)@JonathanWorthington 我不确定您的意思是什么惊喜,也无法说出“这种方法”的哪些细节可能会引发意外。也许我在回答中避免的惊喜(通过引入proto)是(一些?)你正在谈论的惊喜?和/或也许您知道/可以链接到挖掘您正在谈论的内容的现有资源(例如文档部分或 SO)?和/或this 是否适合思考?和/或也许您可以编写一个新的 SO Q+A 对来概述惊喜?
  • @raiph 例如,比较 multi m(Int) { 1 }; multi m(Real) { 2 }; say m 1(名义类型匹配,Int 更紧密)与 subset IntSub where Int; multi m(IntSub) { 1 }; multi m(Real) { 2 }; say m 1subset 表示名义类型 AnyReal更紧)。 proto 方法可以很好地避免这种情况,但意味着重新调度的成本,并且如果多个模块尝试该策略,则不会组合。
【解决方案2】:

您可以在您的类中添加一个Int - 方法并使用signature coercion

class Foo { 
    method Int { 110 };
} 
multi t( Int() $x ) { $x + 1 };
multi t( Real $x ) { $x.Int + 11 };

say t( 0 );
say t( 0.1 );
say t( Foo.new );

【讨论】:

  • 5000 优于 5002
  • @holli - 感谢您的回答,但我需要保留任何值的真实性...例如 $x = Measure.new(value =&gt; 27.5, units =&gt; 'm') + 13.2; say +$x; #40.7
【解决方案3】:

我刚刚在 raku docs 中找到了这个例子:

sub f(*@a where {$_.all ~~ Int}) { say @a };

我现在计划将此与@codesections 答案结合起来...

【讨论】:

    猜你喜欢
    • 2017-10-02
    • 2020-07-20
    • 2021-01-17
    • 1970-01-01
    • 1970-01-01
    • 2015-05-30
    • 1970-01-01
    • 2020-07-21
    • 2011-06-10
    相关资源
    最近更新 更多