【发布时间】:2018-10-28 08:26:34
【问题描述】:
使用.does,我可以检查一个类型是否具有我已经知道的角色。我想获取角色列表。继承有.^mro,但我没有看到元模型中的角色有类似的东西。
除此之外,给定一个“类型”,我如何判断它是定义为类还是角色?
【问题讨论】:
使用.does,我可以检查一个类型是否具有我已经知道的角色。我想获取角色列表。继承有.^mro,但我没有看到元模型中的角色有类似的东西。
除此之外,给定一个“类型”,我如何判断它是定义为类还是角色?
【问题讨论】:
.^roles
say Rat.^roles; # ((Rational[Int,Int]) (Real) (Numeric))
默认情况下它包括所有角色,包括由其他角色引入的角色。只获得第一级使用:!transitive
Rat.^roles(:!transitive); # ((Rational[Int,Int]))
【讨论】:
:transitive 成为默认值的提交。
第一个问题已经有了很好的答案。关于第二个,每个元对象都有一个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
【讨论】:
.^roles 并指出:transitive 选项。
除此之外,给定一个“类型”,我如何判断它是定义为类还是角色?
类是元类的类型为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
【讨论】:
关于你的第二个问题,
给定一个“类型”,我如何判断它是定义为类还是角色?
我还没有找到这样做的直接方法。类和角色的层次结构中都有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 会引发异常。这可以变成一个函数来打印出哪个是角色,哪个不是。
【讨论】: