【问题标题】:How can I discover all the roles a Perl 6 type does?如何发现 Perl 6 类型的所有角色?
【发布时间】:2018-10-28 08:26:34
【问题描述】:

使用.does,我可以检查一个类型是否具有我已经知道的角色。我想获取角色列表。继承有.^mro,但我没有看到元模型中的角色有类似的东西。

除此之外,给定一个“类型”,我如何判断它是定义为类还是角色?

【问题讨论】:

    标签: oop roles raku metamodel


    【解决方案1】:
    .^roles
    
    say Rat.^roles; # ((Rational[Int,Int]) (Real) (Numeric))
    

    默认情况下它包括所有角色,包括由其他角色引入的角色。只获得第一级使用:!transitive

    Rat.^roles(:!transitive); # ((Rational[Int,Int]))
    

    【讨论】:

    • 你在哪里找到的?我在文档中的任何地方都没有看到。我想我应该尝试一下。
    • @briandfoy 我查看了 Rakudo 的每个提交。例如,我阅读了:transitive 成为默认值的提交。
    【解决方案2】:

    第一个问题已经有了很好的答案。关于第二个,每个元对象都有一个archetypes 方法,该方法又携带该元类型表示的类型的一系列属性。这是因为 Perl 6 对新的元类型开放(可能更容易将其视为“类型的类型”);今天使用最广泛的例子可能是OO::Monitors。原型更关注一个人可以用这种类型做什么。例如:

    > role R { }; say "C: {.composable} I: {.inheritable}" given R.HOW.archetypes; 
    C: 1 I: 0
    > class C { }; say "C: {.composable} I: {.inheritable}" given C.HOW.archetypes; 
    C: 0 I: 1
    

    可用属性集可以自省:

    > Int.HOW.archetypes.^methods(:local)
    (nominal nominalizable inheritable inheritalizable composable 
    composalizable generic parametric coercive definite augmentable)
    

    例如,“nominal”的意思是“这可以作为一个名义类型”,而“augmentable”的意思是“是否允许扩充这种类型”。诸如“可继承”之类的意思是“我可以继承这种类型吗”——也就是说,即使我不能从这种类型继承,也可以将它变成我可以继承的类型。一个role是不可继承的,但它是可继承的,对其进行继承操作会产生角色的双关语。这就是在编写 class C is SomeRole { } 之类的东西时发生的事情,这意味着 Perl 6 不仅对新类型开放,而且这些新类型可以描述它们想要如何工作,如果有的话,继承和组合。

    does 可组合可能是角色的主要定义属性,因此composable 属性可能是在询问“这是一个角色”时最好使用的属性。正如另一个答案中所建议的那样,也可以查看元对象的类型,但是表示角色涉及多个元对象(简称角色组,带有参数的该组的柯里化,以及个人角色,以及支持组合过程的内部具体化形式)。

    > say (role RRR[::T] { }).HOW.^name
    Perl6::Metamodel::ParametricRoleHOW
    > say RRR.HOW.^name
    Perl6::Metamodel::ParametricRoleGroupHOW
    > say RRR[Int].HOW.^name
    Perl6::Metamodel::CurriedRoleHOW
    

    因此,简单地检查事物是否可组合更加稳健。

    > say (role RRR[::T] { }).HOW.archetypes.composable
    1
    > say RRR.HOW.archetypes.composable
    1
    > say RRR[Int].HOW.archetypes.composable
    1
    

    【讨论】:

    • 您认为第一个问题的最佳答案是哪一个?
    • @briandfoy Brad Gilbert 建议.^roles 并指出:transitive 选项。
    • 问题是如果它使用 NQP 角色,那将会失败。
    【解决方案3】:

    除此之外,给定一个“类型”,我如何判断它是定义为类还是角色?

    类是元类的类型为Metamodel::ClassHOW的类型:

    sub type-classify(Mu \t) {
        given t.HOW {
            return 'class' when Metamodel::ClassHOW;
            return 'role'  when Metamodel::ParametricRoleGroupHOW;
        }
        return 'other';
    }
    say type-classify(Int);         # class
    say type-classify(Rational);    # role
    say type-classify(Bool);        # other
    

    【讨论】:

      【解决方案4】:

      关于你的第二个问题,

      给定一个“类型”,我如何判断它是定义为类还是角色?

      我还没有找到这样做的直接方法。类和角色的层次结构中都有Mu,因此不会区分它们。然而,只有类才能被(奇怪的名字)MetaModel::ClassHOW 识别。所以我们可以破解这样的东西:

      role Ur { }
      role F does Ur { }
      class G does F { }
      for Ur, F, G -> $class-or-role {
          CATCH {
              default {
                  say "not classy";
              }
          }
          $class-or-role.say;
          $class-or-role.^mro.say;
      }
      

      将打印的内容:

      (Ur)
      not classy
      (F)
      not classy
      (G)
      ((G) (Any) (Mu))
      

      ,因为在角色上调用^mro 会引发异常。这可以变成一个函数来打印出哪个是角色,哪个不是。

      【讨论】:

      • 如果你对角色进行双关,这将失败。角色名称将显示在班级列表中。
      • @briandfoy 如果你双关语,它实际上是“分类”。另外我是在课堂上做的,而不是在一个物体上......
      • 因此我的第二个问题非常具体。
      • 这些都不适合我提到的原因。
      猜你喜欢
      • 2022-09-28
      • 1970-01-01
      • 2017-12-30
      • 1970-01-01
      • 2012-03-30
      • 1970-01-01
      • 1970-01-01
      • 2010-12-29
      • 1970-01-01
      相关资源
      最近更新 更多