提问者:小点点

有没有办法(隐式)删除Raku角色混合?


这个新问题是对我之前提出的问题的跟进。请注意,我也做了一些研究,我有意识地避开了这里提到的标量混合bug。所以我将角色混合到对象中,而不是标量容器中。

大图是做数学运算,也执行简单的错误计算。

这是我失败代码的简明版本:

  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)的值
  • 那么,我怎么才能在第7行左右得到未经修饰的值呢?

我已经(拼命地?)尝试了一些事情:

  • 强制转换为Real(仍然获取混合对象)
  • 分配给Real容器(允许Rat{Error}~~Real)
  • $dog. default=

感谢所有的建议!


共2个答案

匿名用户

对这个问题的直接回答是:不,没有撤消混音的操作。但是,您可以使用一些技巧来实现原始类型的功能:

  • 在方法重写的情况下,使用$obj-with-mixin. OrialType::method-name()表单来调用已被重写的方法。
  • 对于子(例如运算符),您可以执行

然而,看看这个问题和你之前的问题,你似乎每一步都在与语言抗争;是默认的实际上是最后的手段,即使你可以使用混合方法让它工作,你会发现结果非常慢,这在很大程度上是因为混合触发了去优化(从专门的和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;

匿名用户

来自@raiph评论,我已经找到了一个快速而肮脏的修复方法,它使用我知道的事实. 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