当前位置: 首页 > 知识库问答 >
问题:

Raku rebless和多类

都阳辉
2023-03-14

(这是《Raku rebless不再处理继承类》的后续内容)

我试图想出一个更复杂的用例,但无法让代码正常工作。

这个想法是一个Person类,带有儿童和成人的混音子类。我们有一个UNICEF对象,当年龄超过18岁时将类型更改为Adult。

这一点显然是失败的,因为成年人是父母而不是孩子的混合体:

class Person
{
  has Int $.age is rw = 0;

  method happy-birthday
  {
    $.age++;
    # Metamodel::Primitives.rebless($, Adult) if $.age == 18;
  }

  method can-vote
  {
    ...;
  }
}

constant Adult = Person but role { method can-vote { True  } }

constant Child = Person but role
{
  method can-vote { False }
  method happy-birthday
  {
    $.age++;
    Metamodel::Primitives.rebless(self, Adult) if $.age == 18;
  }

}

BEGIN Child.^set_name('Child');
BEGIN Adult.^set_name('Adult');

my $tom   = Child.new;

say "Age  Can-Vote  Class";

for ^20
{
  say "{ $tom.age.fmt('%3d') }   { $tom.can-vote }    { $tom.^name }";
  $tom.happy-birthday;
}

但它部分运行:

Age  Can-Vote  Class
  0   False    Child
  1   False    Child
  2   False    Child
  3   False    Child
  4   False    Child
  5   False    Child
  6   False    Child
  7   False    Child
  8   False    Child
  9   False    Child
 10   False    Child
 11   False    Child
 12   False    Child
 13   False    Child
 14   False    Child
 15   False    Child
 16   False    Child
 17   False    Child
Incompatible MROs in P6opaque rebless for types Child and Adult
  in method happy-birthday at ./vote-error line 28

用一个类和一个混音来设置它是这样的:

class Child
{
  has Int $.age is rw = 0;

  method happy-birthday
  {
    $.age++;
    Metamodel::Primitives.rebless($, Adult) if $.age == 18;
  }

  method can-vote
  {
    False;
  }
}

constant Adult = Child but role { method can-vote { True } }

BEGIN Adult.^set_name('Adult');

my $tom = Child.new;

say "Age  Can-Vote  Class";

for ^20
{
  say "{ $tom.age.fmt('%3d') }   { $tom.can-vote }    { $tom.^name }";
  $tom.happy-birthday;
}

但它不起作用:

 Error while compiling vote-error1
Illegally post-declared type:
    Adult used at line 10

我明白了。rebless系列指的是成年人,尚未公布。所以我试着在课堂上留下痕迹:

class Child { ... }

constant Adult = Child but role { method can-vote { True } }

class Child
{
  has Int $.age is rw = 0;

  method happy-birthday
  {
    $.age++;
    Metamodel::Primitives.rebless($, Adult) if $.age == 18;
  }

  method can-vote
  {
    False;
  }
}

BEGIN Adult.^set_name('Adult');

my $tom = Child.new;

say "Age  Can-Vote  Class";

for ^20
{
  say "{ $tom.age.fmt('%3d') }   { $tom.can-vote }    { $tom.^name }";
  $tom.happy-birthday;
}

但是存根和继承并不相互喜欢:

===SORRY!=== Error while compiling vote-error2
'Child+{<anon|1>}' cannot inherit from 'Child' because 'Child' isn't composed yet (maybe it is stubbed)

然后我尝试添加一个新的mixin以避免循环引用问题:

class Child
{
  has Int $.age is rw = 0;

  method can-vote
  {
    False;
  }
}

constant Adult = Child but role { method can-vote { True } }
BEGIN Adult.^set_name('Adult');

role still-a-child
{
  method happy-birthday
  {
    $.age++;
    Metamodel::Primitives.rebless($, Adult) if $.age == 18;
  }
}

my $tom = Child.new but still-a-child;

say "Age  Can-Vote  Class";

for ^20
{
  say "{ $tom.age.fmt('%3d') }   { $tom.can-vote }    { $tom.^name }";
  $tom.happy-birthday;
}

但这也失败了:

Age  Can-Vote  Class
  0   False    Child+{still-a-child}
  1   False    Child+{still-a-child}
  2   False    Child+{still-a-child}
  3   False    Child+{still-a-child}
  4   False    Child+{still-a-child}
  5   False    Child+{still-a-child}
  6   False    Child+{still-a-child}
  7   False    Child+{still-a-child}
  8   False    Child+{still-a-child}
  9   False    Child+{still-a-child}
 10   False    Child+{still-a-child}
 11   False    Child+{still-a-child}
 12   False    Child+{still-a-child}
 13   False    Child+{still-a-child}
 14   False    Child+{still-a-child}
 15   False    Child+{still-a-child}
 16   False    Child+{still-a-child}
 17   False    Child+{still-a-child}
Cannot change the type of a Any type object
  in method happy-birthday at vote-error3 line 26

它确实做到了,因为$tom现在不是一个孩子,而Adult不是我们现在所拥有的混合体。但是错误消息不是很有帮助。

最后一个与第一个基本相同。

我被困住了。

共有2个答案

仲孙文乐
2023-03-14

非常感谢。但我无法做到:

class Adult { ... }

class Child
{
  has Int $.age is rw = 0;

  method happy-birthday
  {
    $.age++;
    Metamodel::Primitives.rebless(self, Adult) if $.age == 18;
  }

  method can-vote
  {
    False;
  }
}

role grown-up { method can-vote { True } }

class Adult is Child does grown-up { }

my $tom = Child.new;

say "Age  Can-Vote  Class";

for ^20
{
  say "{ $tom.age.fmt('%3d') }   { $tom.can-vote }    { $tom.^name }";
  $tom.happy-birthday;
}

这运行到17,然后失败

New type Adult for Child is not a mixin type

我错过了什么?

(Stackowerflow应该允许注释中的代码。)

商同
2023-03-14

太长别读我描述了几个问题。最后我展示了一个在最近(2020年)Rakudo上编译和运行的解决方案。这是您自己代码的一个简单变体,但我的知识不足以保证其正确性,更不用说适当性了[1][2]

无法更改任何类型对象的类型

错误消息来自rebless行:

Metamodel::Primitives.rebless($, Adult) if $.age == 18;

作为一个术语,[3]并不意味着自己,而是一个匿名状态标量变量。默认情况下,它包含任何代码,因此会显示错误消息。它应该是self[4]

修复了第一个问题后,我们将根据使用的Rakudo版本获得一个新问题:

>

  • 年长的Rakudo:P6中不兼容的MROs为儿童和成人类型重新祝福

    较新的Rakudo:新类型成人儿童不是混音类型

    就像我们刚刚修复的第一条错误消息一样,这两条也是由重新祝福语句触发的。[5]

    我们必须解决这两个问题。

    在较新的Rakudo中,修复无法更改任何类型对象的类型,并且如果我使用您的“添加新的mixin”代码,那么不是mixin类型的问题是不够的;我刚刚收到不兼容的MRO错误。

    相反,如果使用替代代码修复旧Rakudo上不兼容的MRO问题,则除非该问题得到正确解决,否则将导致该问题不是混入类型。(在这个答案的原始版本中,我解决了MRO不兼容的问题,然后忽略了在新的Rakudo上测试!)

    您对不兼容的MROs错误的诊断是“这个显然失败了,因为AdultPerson上的混音,而不是UNICEF上的混音”。我读了这篇文章,看了一眼代码,相信了你,然后继续前进。但是后来我又回到了同一个问题,使用您编写的代码来尝试解决它。是什么给的?

    根据我的实验,似乎不仅“to”类(其类将是正在重新出租的对象的新类)必须具有与正在重新出租的对象兼容的MRO,这符合我的预期(如类继承),而且“from”对象(正在重新出租的对象)也不能同时具有:

    >

  • 基于具有属性的类。

    已混入。

    (我不知道这是一个可以修复的bug还是一个不可避免的限制。我知道最近(2020年)的Rakudo使用了之前SO中Jonathan提供的代码的两个变体,具有此限制。)

    这意味着“添加一个新的mixin以避免循环引用问题”(“存根和继承彼此不喜欢”)并不能解决您的问题。

    相反,我回到了您的“仅一个类和一个mixin”尝试中(最终以您最初编写的形式非法发布声明的类型),并尝试了另一种方法来绕过该错误。

    以下“仅一个类和一个mixin”代码的变体适用于Rakudo v2020.01.114。gcfe。2.cdc。我所做的就是把成人常数变成变量。我已经写了<代码> 对于与您的代码相同的其余代码:

    my $Adult;
    
    ...
        Metamodel::Primitives.rebless(self, $Adult) if $.age == 18;
    ...
    
    $Adult = Child but role { method can-vote { True } }
    $Adult.^set_name('Adult');
    
    ...
    

    Hth。

    [1]Jonathan的解决方案在最近的SO中使用了Adult的编译时构造。我的解决方案遵循Jonathan的示例,只是它在运行时构造了重新祝福的目标$Adult。面对@JonathanWorthington引入的新优化,我不确定这在技术上是否安全。我会尝试“召唤”他对此发表评论。

    除了这个脚注之外,我的回答并没有提到使用rebless的智慧。我立刻想到两个问题。首先是提供了可靠的功能,这对于您甚至需要询问最近的SOs来说都是非常重要的。(也就是说,我们目前在成熟Raku(语言)和Rakudo(实现)的方法上存在漏洞。在某种程度上,我们中的一个人编写的代码填补了漏洞,我们都很感激。)第二个是MOP的可靠文档,因为(据我所知)一些关键文档打破了根据Baast将自身约束为Raku规范的一般规则,而是“在很大程度上反映了Rakudo-Raku编译器实现的元对象系统”。我只是解决错误,直到您的代码在2020版本的Rakudo上编译和运行时没有错误。

    参见术语是什么?与此评论中的某些上下文链接。

    一些人可能会认为如果$。foo是一个。fooofself,则$必须是self。如果raku拥有大多数编程语言所使用的典型上下文无关标记化,那么这种想法将是一种合理的假设。此外,它通常也适用于Raku代码,就像它通常甚至适用于自然语言一样。(如果英语标记“my”后跟“self”,那么它很可能与“my”的意思相同。)但Raku的语法故意将上下文敏感性、无扫描解析和最大咀嚼结合起来,以支持创建比编程语言更自然的感觉语言。这里我们看到一个例子。在“术语位置”中,输入“<代码>$”。foo被识别为单个标记,而不是两个($后接.foo),而输入$被识别为两个标记($,后跟列表分隔符操作符,),而不是一个。

    [5]所有这些错误消息都是在Rakudo靠近金属的部分生成的。如果您使用MoarVM作为后端,它们来自其P6opaque. c文件。

  •  类似资料:
    • 校验者: @溪流-十四号 @大魔王飞仙 翻译者: @v Warning All classifiers in scikit-learn do multiclass classification out-of-the-box. You don’t need to use the sklearn.multiclass module unless you want to experiment with

    • 问题内容: 假设我有一个数据库,其中包含人员,杂货店和您可以在商店中购买的商品,如下所示: 我还有一个表格可以跟踪哪些商店销售什么: 我还有一张桌子上有购物清单 我的问题是,给定一个人或他们的ID,找出他们可以去的商店的最佳方法是什么,以便他们将所有物品都列入清单。MySQL中是否有针对这些类型的计算的模式? 我的尝试(非常丑陋和凌乱)是这样的: 谢谢你的时间! 使用数据编辑SQL 问题答案: 如

    • 在面向对象编程中,当我们已经创建了一个类,而又想再创建一个与之相似的类,比如添加几个方法,或者修改原来的方法,这时我们不必从头开始,可以从原来的类派生出一个新的类,我们把原来的类称为父类或基类,而派生出的类称为子类,子类继承了父类的所有数据和方法。 让我们看一个简单的例子,首先我们定义一个 Animal 类: class Animal(object): def __init__(self,

    • 多任务是一个操作系统可以同时执行多个程序的能力。基本上,操作系统使用一个硬件时钟为同时执行的每个程序配置「时间片段」。如果时间片段够小,并且机器也没有由于太多的程序而超出负荷时,那么在使用者看来,所有的这些程序似乎在同时执行着。 多任务并不是什么新的东西。在大型计算机上,多任务是必然的。这些大型主机通常有几十甚至几百个终端机和它连结,而每个终端机使用者都应该感觉到他或者她独占了整个计算机。另外,大

    • 之前提到Vert.x API是事件驱动 - 当他们都可用时,Vert.x传递事件给处理程序。 在大多数情况下Vertx要求使用一种称为event loop线程的处理程序。 如无有 Vert.x 或您的应用程序块中,event loop可以欢快地运行将事件传递给不同的处理程序提供事件陆续到达。 因为没有阻塞,event loop可以在短时间内提供大量的事件。例如一个单一的event loop可以非常

    • 我在当前项目中使用Sass(.scss)。 以下示例: HTML SCSS 这个很管用。 我可以处理多个类,同时使用嵌套样式。 在上面的示例中,我讨论了以下内容: CSS 在这种情况下,所有通常为,但为蓝色。 我如何在中与Sass嵌套?