我该如何发现Perl 6类型扮演的所有角色?

12

使用.does操作符,我可以检查一个类型是否扮演了我已知的角色。我想获得角色列表。继承有.^mro,但是在元模型中没有类似于角色的东西。

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

4个回答

13
.^roles
say Rat.^roles; # ((Rational[Int,Int]) (Real) (Numeric))

默认情况下,它包括每个角色,包括其他角色引入的角色。要仅获取第一级,请使用:!transitive

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

2
你在哪里找到的?我在文档中没看到过。我想我应该尝试一下。 - brian d foy
2
@briandfoy 我查看Rakudo的每个提交。例如,我阅读了:transitive成为默认设置的提交。 - Brad Gilbert

9

关于第一个问题已经有了一个很好的答案。对于第二个问题,每个元对象都有一个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)

例如,“名义上”意味着“这能作为一种名义类型吗”,而“可增加性”意味着“是否允许增加此类类型”。像“可继承性”之类的东西意味着“我能继承这样的类型吗”,也就是说,即使无法从该类型继承,我仍可以将其转换为我可以继承的类型。角色(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

1
你认为第一个问题的正确答案是哪个? - brian d foy
2
@briandfoy,来自Brad Gilbert的建议是使用.^roles并指出使用:transitive选项。 - Jonathan Worthington
问题在于,如果它使用了NQP角色,那么会失败。 - jjmerelo

6
除此之外,针对给定的“type”,我如何判断它是定义为类还是角色?
类是一种元类为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

1
关于您的第二个问题,
给定一个“类型”,如何判断它是定义为类还是角色?
我没有找到直接的方法。类和角色在它们的层次结构中都有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会引发异常,因此可以将其转换为打印哪个是角色,哪个不是的函数。


如果您在角色上打了双关语,这将失败。角色名称将显示在类列表中。 - brian d foy
@briandfoy如果你把它当做双关语,那么它就是“分类”的意思。而且我是在类上操作,而不是在对象上... - jjmerelo
因此,我的第二个问题非常具体。 - brian d foy
@briandfoy 和我的回答中的hack实际上是将你的第一个问题转换为回答第二个问题的 :-) 无论如何,这只是一个hack。 - jjmerelo
这两个都不适合我提到的原因。 - brian d foy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接