枚举是如何扩充的?

Kai*_*epi 8 enums metaprogramming raku

在 Raku 中,HOW 必须通过一种方法公开原型列表,该archetypes方法用于确定类型实现哪些更广泛的类型特征,例如参数性或可组合性。我注意到Metamodel::EnumHOW(与枚举一起使用的 HOW)具有augmentable原型,它被赋予在启用 pragmaaugment时使用关键字组合后可以扩展的类型MONKEY-TYPING

我对为什么枚举可以增加的第一个猜测是允许添加枚举值,所以我尝试写这个:

use v6;
use MONKEY-TYPING;

enum Foo <foo bar baz>;
augment enum Foo <qux>;
say qux;
Run Code Online (Sandbox Code Playgroud)

但这会抛出:

bastille% raku test.raku
===SORRY!=== Error while compiling /home/morfent/test.raku
Redeclaration of symbol 'Foo'.
at /home/morfent/test.raku:5
------> augment enum Foo? <qux>;
Run Code Online (Sandbox Code Playgroud)

因此,它们可能不打算以这种方式增强。

我的下一个猜测是,它们旨在针对枚举值而不是枚举类型本身进行扩充。augment,有趣的是,当您告诉它您要扩充哪种类型时,并没有考虑到类型实际具有的内容,因此我尝试像增加类一样扩充枚举:

use v6;
use MONKEY-TYPING;

enum Foo <foo bar baz>;

augment class Foo {
    proto method is-foo(::?CLASS:D: --> Bool:D) {*}
    multi method is-foo(foo: --> True)          { }
    multi method is-foo(::?CLASS:D: --> False)  { }
}

say foo.is-foo;
Run Code Online (Sandbox Code Playgroud)

哪个有效:

bastille% raku test.raku
True
Run Code Online (Sandbox Code Playgroud)

但这并不像你打算如何为我增加枚举。的这种用法augment相当奇怪,并且没有任何暗示可以从其文档中做到这一点。你打算如何增加枚举?

常问问题

  • Foo.is-foo似乎没有任何代码?它在做什么?

is-foo对它如何使用签名和参数的特征相当严厉。这取决于以下几点:

  • 常量值可以像签名中的类型一样使用。这包括在编译时处理的枚举值。
  • 通过将其签名的返回值类型设置为一个例程,可以使例程始终返回一个常量值。
  • 签名中任何给定参数的变量都是可选的。
  • 当一个冒号像这样放在第一个参数之后时,第一个参数就是签名的invocant。在方法的情况下,这允许您随意键入self
  • ::?CLASS是在其范围内声明方法的类的别名。它存在于类和角色主体中,因此尽管Foo不是真正的类,但这就是符号所指的内容。
  • :D 是一个类型笑脸,表示一个类型应该只针对它自己的实例进行类型检查,而不是类型检查喜欢它的类型对象。

由于foo是比::?CLASS:D( 的别名Foo:D)更具体的类型,当在 上调用此方法时foofoo将选择多并True返回,但在任何其他情况下,::?CLASS:D多将被选择并False返回。

bob*_*ian 6

在 Java 中,您几乎可以向枚举添加任意属性和函数。所以我确实认为你描述的方式增加是有道理的。例如:

use MONKEY-TYPING;

enum Days(Monday => 1, Tuesday => 2, Wednesday => 3, Thursday => 4, Friday => 5, Saturday => 6, Sunday => 7); 

augment class Days {
    proto method is-weekend(::?CLASS:D: --> Bool:D) {*} 
    multi method is-weekend(Saturday: --> True)          { } 
    multi method is-weekend(Sunday: --> True) {}
    multi method is-weekend(::?CLASS:D: --> False)  { } 

    proto method days-til-weekend(::?CLASS:D: --> Int:D) {*}
    # there is probably a better way to express this, but
    # hopefully the concept is clear
    multi method days-til-weekend(Monday: --> 4) {}
    ...
}

say Monday.is-weekend;
say Wednesday.days-til-weekend;
say Saturday.is-weekend;
Run Code Online (Sandbox Code Playgroud)