operator-overloading - 用于实例化参数化角色的对象的重载运算符
问题描述
在 C++ 中,您可以创建在模板化对象上使用特定运算符的模板化类,并且实例化这些对象的类必须重载该特定运算符才能使其对象与模板化类一起使用。例如,insertion
BST 实现的方法可能依赖于<
运算符,因此要存储在 BST 中的任何对象都必须实现该运算符。
如果可能的话,我怎样才能对 Raku 中的参数化角色做同样的事情?
为了提供一些上下文,例如以下参数化角色定义为它自己的模块:
role BST[::T] {
my role BinaryNode[::T] {
has T $.item is rw;
has BinaryNode $.left is rw;
has BinaryNode $.right is rw;
}
has BinaryNode $!root;
method insert( BST:D: T $x --> Nil ) {
self!rec-insert($x, $!root)
}
method !rec-insert( T $x, BinaryNode $node is rw --> Nil ) {
if !$node.defined { $node = BinaryNode[$(T)].new(item => $x) }
elsif $x < $node.item { self!rec-insert($x, $node.left) }
elsif $node.item < $x { self!rec-insert($x, $node.right) }
else { } # Duplicate; do nothing
}
}
然后,它可以用来存储整数:
use BST;
my $bst = BST[Int].new;
$bst.insert($_) for 6, 3, 2, 1, 4;
但是,尝试一些用户定义的类型我无法使其工作。假设我们已经定义了一个Point2D
类,并且两个对象之间的小于关系Point2D
由它们到中心的距离定义(例如,Point2D.new(:3x, :4x)
小于Point2D.new(:6x, :8y)
):
use BST;
class Point2D {
has $.x;
has $.y;
multi method distance {
(($!x - 0) ** 2 ($!y - 0) ** 2).sqrt
}
}
multi infix:«<»( Point2D:D $lhs, Point2D:D $rhs --> Bool ) {
return $lhs.distance < $rhs.distance
}
my $bst = BST[Point2D].new;
$bst.insert(Point2D.new(:1x, :4y));
$bst.insert(Point2D.new(:3x, :4y));
=begin comment
Cannot resolve caller Real(Point:D: ); none of these signatures match:
(Mu:U \v: *%_)
in method rec-insert ...
in method insert ...
=end comment
我不太受过教育的猜测是运算符<
forPoint2D
是词法的,因此BST
不会选择它。如果在一个模块中重载了一个操作符,建议将它导出,这样它就可以被用户use
或者import
模块使用。但是,我认为这没有多大意义,BST
因为特定类的对象将以不同的方式定义它们的关系关系。此外,我什至不确定这是否适用于类型捕获。
解决方案
中缀<
运算符用于比较实数。
您希望它以数字方式比较 的值.distance
。
如果您尝试将对象用作实数以使其自动强制到距离,这也许是有道理的。
class Point2D {
has $.x;
has $.y;
method distance {
(($!x - 0) ** 2 + ($!y - 0) ** 2).sqrt
}
method Real { self.distance } # <-----
}
然后内置<
自动做正确的事情。
我个人会添加一些类型和其他注释。
这也使得($!x - 0)
它的等价物(+$!x)
毫无意义。
class Point2D {
has Real ( $.x, $.y ) is required;
method distance (--> Real) {
sqrt( $!x² + $!y² );
}
method Real (--> Real) { self.distance }
}
cmp
向 Raku 添加一个功能以进行通用比较 ( , before
, after
)可能是有意义的
目前,那些调用.Stringy
这两个值并比较它们。
.Stringy
您目前可以通过使用返回不执行Stringy角色的方法的方法来滥用它。
也许它可以像这样工作:
role Comparable {
method COMPARE () {…}
}
class Point does Comparable {
has Real ( $.x, $.y ) is required;
method distance (--> Real) {
sqrt( $!x² + $!y² );
}
method COMPARE () {
($.distance, $!x, $!y)
}
}
multi sub infix:<cmp> ( Comparable \left, Comparable \right ) {
nextsame unless left.WHAT =:= right.WHAT;
return Same if left =:= right;
return Same if left eqv right;
left.COMPARE() cmp right.COMPARE()
}
.distance
届时.x
将进行上述比较.y
。
(当然,在这种情况下,这可能没有多大意义。)
推荐阅读
- r - 如何用R中的行交换列
- python - python列表中的vlookup
- c# - 如何有一个'a'到'z'的列表?
- .net-core - 在 Blazor WebAssembly 应用程序中,浏览器中下载的 .Net Framework DLL 何时转换为 WebAssembly?
- python - 在 python 中执行 PowerShell 行
- c++ - 数组类型 int[] 不可赋值
- go - 在 Golang 中作为参数传递的“抽象”构造函数方法
- ios - 如何使用自定义动画选择性地为 CALayer 的属性设置动画
- javascript - 在 WooCommerce 中显示选定的变体
- php - PHP 为数组元素分配新值