Как можно дополнять перечисления?

#enums #metaprogramming #raku

#перечисления #метапрограммирование #раку

Вопрос:

В Raku HOWs должен предоставлять список архетипов с помощью archetypes метода, который используется для определения того, какие более широкие возможности типов реализует тип, например параметричность или компоноваемость. Я заметил, что Metamodel::EnumHOW (КАК используется с перечислениями) имеет augmentable архетип, который присваивается типам, которые могут быть расширены после композиции с augment ключевым словом, когда MONKEY-TYPING включена прагма.

Мое первое предположение о том, почему перечисления можно было бы дополнять, заключалось бы в том, чтобы разрешить добавление значений перечислений, поэтому я попытался написать это:

 use v6;
use MONKEY-TYPING;

enum Foo <foo bar baz>;
augment enum Foo <qux>;
say qux;
  

Но это бросает:

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

Таким образом, они, вероятно, не предназначены для расширения таким образом.

Мое следующее предположение состояло в том, что они предназначены для расширения в отношении значений перечисления, а не самого типа перечисления. 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;
  

Что работает:

 bastille% raku test.raku
True
  

Но это не похоже на то, как вы собираетесь дополнять перечисления для меня. Такое использование augment довольно странно, и нет никаких указаний на то, что это должно быть возможно сделать из его документации. Как вы собираетесь увеличивать перечисления?

Вопросы и ответы

  • Foo.is-foo похоже, что в нем нет никакого кода? Что это делает?

is-foo довольно сложно использовать особенности подписей и параметров. Это зависит от следующего:

  • Постоянные значения могут использоваться как типы в подписях. Сюда входят значения перечислений, которые обрабатываются во время компиляции.
  • Можно настроить процедуру так, чтобы она всегда возвращала постоянное значение, задав тип возвращаемого значения для своей подписи.
  • Переменные для любого заданного параметра в подписи являются необязательными.
  • Когда после первого параметра ставится двоеточие, подобное этому, этот первый параметр является вызывающим параметром подписи. В случае методов это позволяет вам вводить self то, что вы хотите.
  • ::?CLASS является псевдонимом для класса, в области видимости которого объявлен метод. Это существует в телах классов и ролей, поэтому, несмотря на то, что Foo на самом деле это не класс, это то, на что ссылается символ.
  • :D смайлик типа означает, что тип должен проверять тип только на своих собственных экземплярах, а не на объектах типа, которые проверяют тип, как это.

Поскольку foo это более конкретный тип, чем ::?CLASS:D (псевдоним для Foo:D ), при вызове этого метода на foo будет выбрано foo несколько и True будет возвращено, но в любом другом случае будет выбрано ::?CLASS:D несколько и False будет возвращено.

Ответ №1:

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