如何在Perl 6中将类设为参数化? [英] How can classes be made parametric in Perl 6?

查看:69
本文介绍了如何在Perl 6中将类设为参数化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常在Perl 6中,只允许角色角色化.在这里,我们将尝试创建类,一种种类(从此处引用)作为元对象)通常是不允许参数化,参数化的.

如果您尝试以天真的方式使类参数化,则会发生这种情况:

bastille% perl6 -e 'class Foo[::T] {}'
===SORRY!=== Error while compiling -e
Unable to parse class definition
at -e:1
------> class Foo⏏[::T] {}
    expecting any of:
        generic role

但是,如果您查看一下NativeCall中的CArray类型使用的元对象,您会发现它实际上是一个类,而不是角色,但它仍然是参数化的!

bastille% perl6 -MNativeCall -e 'say CArray[int32].HOW.^name'
Perl6::Metamodel::ClassHOW+{<anon>}+{<anon>}

这是怎么做的?

解决方案

使类参数化需要一些元编程来完成.可以像这样实现一个简单的参数容器类:

use v6.d;

class Container {
    my role ContainerImpl[::T] {
        has T $.value;

        method new(Container: T $value) {
            self.bless: :$value
        }

        multi method gist(Container:D: --> Str:D) {
            $!value.gist
        }
        multi method Str (Container:D: --> Str:D) {
            $!value.Str
        }
        multi method perl(Container:D: --> Str:D) {
            self.^name ~ '.new(' ~ $!value.perl ~ ')'
        }
    }

    method ^parameterize(Mu:U \this, Mu \T) {
        my $type := this.^mixin: ContainerImpl[T];
        $type.^set_name: this.^name ~ '[' ~ T.^name ~ ']';
        $type
    }
}

say Container[Int].new(1).perl;
# OUTPUT: Container[Int].new(1)

那么这是怎么工作的?

充当Perl6::Metamodel::MetaMethodContainer角色的元类(例如Perl6::Metamodel::ClassHOW)可以将其他元方法与类型的专有技术混合在一起(该知识描述了特定类型的类型,例如类或角色的行为). Rakudo的语法在解析类型名称时,以参数类型和任何参数化类型为参数,对任何给定类型调用parameterize元方法.通常,应该将参数化类型实现参数化原型,但这在这里不做检查,只要实现parameterize元方法,就可以对任何类型的参数进行参数化. >

mixin元方法特定于Perl6::Metamodel::Mixins角色,Perl6::Metamodel::ClassHOW也是如此.该方法通过重载类来混合角色,因此它被认为是与传递给它的(在这种情况下为参数化)角色相同的类型.

结合使用parameterizemixin元方法,您可以在角色中实现参数行为,然后通过在混合之前对其进行参数化来在类中使用它.这使类的行为就像实际上是参数化的一样.类型,即使从技术上讲它仍然不是一个.

Normally in Perl 6, only roles are allowed to be parametric. Here, we'll be attempting to make classes, a kind (referred to from here on out as a metaobject) that isn't normally allowed to be parametric, parametric.

If you try to make a class parametric the naive way, this happens:

bastille% perl6 -e 'class Foo[::T] {}'
===SORRY!=== Error while compiling -e
Unable to parse class definition
at -e:1
------> class Foo⏏[::T] {}
    expecting any of:
        generic role

But if you take a look at what metaobject the CArray type from NativeCall uses, you'll find that it's in fact a class, not a role, yet it's still parametric!

bastille% perl6 -MNativeCall -e 'say CArray[int32].HOW.^name'
Perl6::Metamodel::ClassHOW+{<anon>}+{<anon>}

How is this done?

解决方案

Making classes parametric takes a little bit of metaprogramming to accomplish. A simple parametric container class can be implemented like so:

use v6.d;

class Container {
    my role ContainerImpl[::T] {
        has T $.value;

        method new(Container: T $value) {
            self.bless: :$value
        }

        multi method gist(Container:D: --> Str:D) {
            $!value.gist
        }
        multi method Str (Container:D: --> Str:D) {
            $!value.Str
        }
        multi method perl(Container:D: --> Str:D) {
            self.^name ~ '.new(' ~ $!value.perl ~ ')'
        }
    }

    method ^parameterize(Mu:U \this, Mu \T) {
        my $type := this.^mixin: ContainerImpl[T];
        $type.^set_name: this.^name ~ '[' ~ T.^name ~ ']';
        $type
    }
}

say Container[Int].new(1).perl;
# OUTPUT: Container[Int].new(1)

So how does this work?

Metaclasses that do the Perl6::Metamodel::MetaMethodContainer role, such as Perl6::Metamodel::ClassHOW, can have additional metamethods mixed in with the type's knowhow (which describes how a specific kind of type, such as a class or role, behaves). Rakudo's grammar invokes the parameterize metamethod on any given type with the parametric type and any parameterized types as arguments when parsing a type's name. Normally, types that are parametric are supposed to implement the parametric archetype, but this doesn't get checked here, which allows any type to be parameterized as long as it implements a parameterize metamethod.

The mixin metamethod is specific to the Perl6::Metamodel::Mixins role, which Perl6::Metamodel::ClassHOW also does. The method mixes in a role by reblessing the class so it's considered to be the same type as the (parameterized in this case) role passed to it.

Combining the parameterize and mixin metamethods allows you to implement parametric behaviour in a role, then use it in a class by parameterizing it before mixing it in. This allows the class to behave as if it actually were a parametric type, even though it's still technically not one.

这篇关于如何在Perl 6中将类设为参数化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆