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

Posted

技术标签:

【中文标题】有没有办法(隐式)删除 Raku 角色混合?【英文标题】:Is there a way to (implicitly) drop a Raku role mixin? 【发布时间】:2021-11-05 03:13:01 【问题描述】:

这个新问题是对我的previous 的后续跟进,随着我的充实而出现。请注意,我也做了一些研究,我有意识地避开提到的 Scalar Mixins 错误 here。所以我将角色混合到对象而不是标量容器中。

大局是进行数学运算,同时执行简单的误差计算。

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

  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 => 'Rat+Error' 类型的调用者没有这种方法'default'

谢谢大家的建议!!

【问题讨论】:

【参考方案1】:

对所提出问题的直接回答:不,没有撤消 mixin 的操作。但是,您可以采取一些技巧来实现原始类型的功能:

在方法覆盖的情况下,使用$obj-with-mixin.OriginalType::method-name() 形式调用已被覆盖的方法。 在multi子的情况下(比如操作符),你可以用&amp;prefix:&lt;-&gt;.cando(\(1.5)).head来解析-Rat上的实现,而不是调用,然后直接调用。

然而,看看这个问题和你的previous one,你似乎每一步都在与语言作斗争; 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;

【讨论】:

感谢@jnthn - 这非常有道理,我有一种观点认为,mixin 将通过另一条路线解决这个问题(由于二元数学运算符的签名可确定性)当一个是 Error 而另一个是 Real 时)...我没有想过将 Real 组合到 Error 类中...会玩的!【参考方案2】:

离开@raiphs 评论后,我想出了一个快速而肮脏的修复方法,它利用我知道 .say 方法可以产生 Object 的朴素值这一事实......

...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

【讨论】:

以上是关于有没有办法(隐式)删除 Raku 角色混合?的主要内容,如果未能解决你的问题,请参考以下文章

如何强制编译器显示隐式构造函数

有没有办法避免隐式转换为 void*?

有没有办法定义全局 Makefile(隐式)规则?

有没有办法隐式地使按钮成为多行?

在 MongoDB 中建模访问控制

可以在编译时隐式引用类名吗?