How can I discover all the roles a Perl 6 type does?

耗尽温柔 提交于 2019-12-06 20:24:51

问题


With .does I can check if a type has the role I already know. I'd like to get the list of roles. Inheritance has .^mro but I didn't see anything like that for roles in the meta model stuff.

Along with that, given a "type", how can I tell if it was defined as a class or a role?


回答1:


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

By default it includes every role, including roles brought in by other roles. To only get the first level use :!transitive

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



回答2:


There's already a good answer to the first question. About the second one, each meta-object has an archetypes method that in turn carries a range of properties of the types represented by that meta-type. This exists because Perl 6 is open to new meta-types (which might be easier to think about as "types of type"); probably the most widely used example of this today is OO::Monitors. The archetypes are more focused on what one can do with the type. For example:

> 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

The set of available properties can be introspected:

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

For example, "nominal" means "can this serve as a nominal type", and "augmentable" means "is it allowed to augment this kind of type". The things like "inheritalizable" mean "can I inheritalize such a type" - that is, turn it into a type that I can inherit from even if I can't inherit from this type. A role is not inheritable, but it is inheritalizable, and the inheritalize operation on it will produce the pun of the role. This is what is happening under the hood when writing something like class C is SomeRole { }, and means that not only is Perl 6 open to new types of type, but those new types of type can describe how they want to work, if at all, with inheritance and composition.

Being composable with does is probably the main defining property of a role, and thus the composable property is likely the best one to use when asking "is this a role". It is also possible to look at the type of the meta-object, as suggested in another answer, but there are multiple meta-objects involved in representing roles (the short name role group, a currying of that group with parameters, and an individual role, plus an internal concretization form that supports the composition process).

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

Thus it's rather more robust to simply check if the thing is composable.

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



回答3:


Along with that, given a "type", how can I tell if it was defined as a class or a role?

A class is a type whose meta class is of 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



回答4:


Regarding your second question,

given a "type", how can I tell if it was defined as a class or a role?

I haven't found a direct way of doing that. Both classes and roles have Mu in their hierarchy, so that will not distinguish them. However, only classes get to be recognized by (the curiously named) MetaModel::ClassHOW. So we can hack something like this:

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;
}

Which will print:

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

, since calling ^mro on a role will raise an exception. That can be turned into a function for printing out which one is a role, and which is not.



来源:https://stackoverflow.com/questions/50402115/how-can-i-discover-all-the-roles-a-perl-6-type-does

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!