如何将一个签名测试应用于多个位置
How to apply one signature test to multiple positionals
我在 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 测试应用于两个 Positionals,如果两者或一个匹配但不匹配,则触发 multi,并且保留位置不妥协的行动 <[-/]>?
我不确定没有多重是最优雅的 - 也许只是将 Real-Measure 和 Measure-Real 压缩为一个?
有几种方法可以解决这个问题,但我可能会做的——也是一个通常有用的模式——是使用 subset to create a slightly over-inclusive multi and then redispatch 你不应该包括的案例。对于您提供的示例,它可能看起来有点像:
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
测试这段代码;如果它不起作用请告诉我。但总体思路应该是可行的。)
您可以添加一个 Int
- 方法到您的 class 并使用 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 );
我刚在 raku 中找到这个例子 docs:
sub f(*@a where {$_.all ~~ Int}) { say @a };
我现在计划将其与@codesections 的答案结合起来...
我在 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 测试应用于两个 Positionals,如果两者或一个匹配但不匹配,则触发 multi,并且保留位置不妥协的行动 <[-/]>?
我不确定没有多重是最优雅的 - 也许只是将 Real-Measure 和 Measure-Real 压缩为一个?
有几种方法可以解决这个问题,但我可能会做的——也是一个通常有用的模式——是使用 subset to create a slightly over-inclusive multi and then redispatch 你不应该包括的案例。对于您提供的示例,它可能看起来有点像:
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
测试这段代码;如果它不起作用请告诉我。但总体思路应该是可行的。)
您可以添加一个 Int
- 方法到您的 class 并使用 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 );
我刚在 raku 中找到这个例子 docs:
sub f(*@a where {$_.all ~~ Int}) { say @a };
我现在计划将其与@codesections 的答案结合起来...