有没有办法(隐含地)删除 Raku 角色混合?
Is there a way to (implicitly) drop a Raku role mixin?
这个新问题是我 that has emerged as I flesh things out. Please note that I have also done some research and I am consciously skirting the Scalar Mixins bug mentioned 的后续问题。所以我将角色混合到对象而不是标量容器中。
大局是进行数学运算,同时执行简单的误差计算。
这是我的失败代码的简明版本:
1 role Error {
2 has $.abs-error
3 }
4
5 multi prefix:<-> ( Error:D $x ) is default {
6 # - $x; # fails - enters an infinite loop
7 # - $x.Real; # fails - does not drop the Error mixin
8 ( 0 - $x ) does Error($x.abs-error) # works - but relies on the infix:<-> form
9 }
10
11 my $dog = 12.5 does Error(0.5);
12
13 #what i have...
14 say $dog; #12.5
15 say $dog.WHAT; #(Rat+{Error})
16 say $dog.abs-error; #0.5
17
18 #what i want...
19 say (-$dog); #-12.5
20 say (-$dog).WHAT; #(Rat+{Error})
21 say (-$dog).abs-error; #0.5
我的问题的核心是:
- 作为 $dog 的用户,我 可以 获取第 14 行的变量 (12.5) 的值
- sooo 我怎样才能得到第 7 行附近某处的原始值?
我已经(拼命地?)尝试了一些事情:
- 强制转换为 Real(仍然得到混合对象)
- 分配给 Real 容器(允许 Rat+{Error} ~~ Real)
- $dog.default => 对于 'Rat+{Error}'
类型的调用者没有这样的方法 'default'
谢谢大家的建议!!
根据@raiphs 的评论,我想出了一个快速而肮脏的修复方法,它使用了一个事实,即我知道 .say 方法可以产生对象的原始值...
... OO编程纯粹主义者,请移开视线。
1 role Error {
2 has $.abs-error;
3
4 method negate {
5 my $val = +"{self}"; #extract unadorned value of $x
6 (- $val) does Error( $!abs-error );
7 }
8 }
9
10 multi prefix:<-> ( Error:D $x ) is default { $x.negate }
11
12 my $dog = 12.5 does Error(0.5);
13
14 #what i get...
15 say (-$dog); #-12.5
16 say (-$dog).WHAT; #(Rat+{Error})
17 say (-$dog).abs-error; #0.5
对所提出问题的直接回答:不,没有撤消混入的操作。您可以做一些技巧来实现原始类型的功能,但是:
- 在方法覆盖的情况下,使用
$obj-with-mixin.OriginalType::method-name()
形式调用已被覆盖的方法。
- 在
multi
子(例如运算符)的情况下,您可以执行 &prefix:<->.cando(\(1.5)).head
来解析,但不能调用 [=15] 上的 -
的实现=],然后直接调用。
然而,看看这个问题和你的 ,你似乎每一步都在与语言作斗争; is default
确实是最后的手段,即使你可以使用 mixin 方法让它工作,你也会发现结果非常慢,这在很大程度上是因为 mixins 触发了去优化(脱离了专门化和 JIT -编译后的代码返回给解释器)。
也许探索使用组合的设计:
# An object holding the value and the error.
class Error does Real {
has Real $.value;
has Real $.abs-error;
multi method Real(Error:D:) { $!value }
multi method gist(Error:D:) { "$!value±$!abs-error" }
}
# A cute constructor of this type, just for fun.
multi infix:<±>(Real $value, Real $abs-error) {
Error.new(:$value, :$abs-error)
}
# Negation; no `is default` or other tricks required!
multi prefix:<->(Error $e --> Error) {
Error.new(value => -$e.value, abs-error => $e.abs-error)
}
# It works!
my $x = 4.5 ± 0.1;
say $x;
say -$x;
这个新问题是我
大局是进行数学运算,同时执行简单的误差计算。
这是我的失败代码的简明版本:
1 role Error {
2 has $.abs-error
3 }
4
5 multi prefix:<-> ( Error:D $x ) is default {
6 # - $x; # fails - enters an infinite loop
7 # - $x.Real; # fails - does not drop the Error mixin
8 ( 0 - $x ) does Error($x.abs-error) # works - but relies on the infix:<-> form
9 }
10
11 my $dog = 12.5 does Error(0.5);
12
13 #what i have...
14 say $dog; #12.5
15 say $dog.WHAT; #(Rat+{Error})
16 say $dog.abs-error; #0.5
17
18 #what i want...
19 say (-$dog); #-12.5
20 say (-$dog).WHAT; #(Rat+{Error})
21 say (-$dog).abs-error; #0.5
我的问题的核心是:
- 作为 $dog 的用户,我 可以 获取第 14 行的变量 (12.5) 的值
- sooo 我怎样才能得到第 7 行附近某处的原始值?
我已经(拼命地?)尝试了一些事情:
- 强制转换为 Real(仍然得到混合对象)
- 分配给 Real 容器(允许 Rat+{Error} ~~ Real)
- $dog.default => 对于 'Rat+{Error}' 类型的调用者没有这样的方法 'default'
谢谢大家的建议!!
根据@raiphs 的评论,我想出了一个快速而肮脏的修复方法,它使用了一个事实,即我知道 .say 方法可以产生对象的原始值...
... OO编程纯粹主义者,请移开视线。
1 role Error {
2 has $.abs-error;
3
4 method negate {
5 my $val = +"{self}"; #extract unadorned value of $x
6 (- $val) does Error( $!abs-error );
7 }
8 }
9
10 multi prefix:<-> ( Error:D $x ) is default { $x.negate }
11
12 my $dog = 12.5 does Error(0.5);
13
14 #what i get...
15 say (-$dog); #-12.5
16 say (-$dog).WHAT; #(Rat+{Error})
17 say (-$dog).abs-error; #0.5
对所提出问题的直接回答:不,没有撤消混入的操作。您可以做一些技巧来实现原始类型的功能,但是:
- 在方法覆盖的情况下,使用
$obj-with-mixin.OriginalType::method-name()
形式调用已被覆盖的方法。 - 在
multi
子(例如运算符)的情况下,您可以执行&prefix:<->.cando(\(1.5)).head
来解析,但不能调用 [=15] 上的-
的实现=],然后直接调用。
然而,看看这个问题和你的 is default
确实是最后的手段,即使你可以使用 mixin 方法让它工作,你也会发现结果非常慢,这在很大程度上是因为 mixins 触发了去优化(脱离了专门化和 JIT -编译后的代码返回给解释器)。
也许探索使用组合的设计:
# An object holding the value and the error.
class Error does Real {
has Real $.value;
has Real $.abs-error;
multi method Real(Error:D:) { $!value }
multi method gist(Error:D:) { "$!value±$!abs-error" }
}
# A cute constructor of this type, just for fun.
multi infix:<±>(Real $value, Real $abs-error) {
Error.new(:$value, :$abs-error)
}
# Negation; no `is default` or other tricks required!
multi prefix:<->(Error $e --> Error) {
Error.new(value => -$e.value, abs-error => $e.abs-error)
}
# It works!
my $x = 4.5 ± 0.1;
say $x;
say -$x;