Может ли Perl 6 использовать сигил % для чего-то другого, кроме хэша?


В документах Perl 6 по переменным отмечается, что Сигилла % может использоваться с типами, выполняющими ассоциативную роль . Он специально упоминает пару, хэш иКарта . Но как я могу получить пару в переменную с %?

Если я использую ограничение типа, я получаю любопытную ошибку:

> my Pair %pair = Pair.new( 'a', 'b' )
Type check failed in assignment to %pair; expected Pair but got Str ("b")
  in block <unit> at <unknown file> line 1

Если я назначаю без ограничения типа, я получаю хэш:

my %pair = Pair.new: 'a', 'b';  # Hash, not Pair

Переплетные работы:

my %pair := Pair.new: 'a', 'b';  # Pair

Но если я использую ограничение типа, Я получаю еще одну любопытную ошибку:

> my Pair %p2 := Pair.new: 'a', 'b';
Type check failed in binding; expected Associative[Pair] but got Pair (:a("b"))
  in block <unit> at <unknown file> line 1

Та же проблема возникает с мешком и набором. Сделайте это с помощью Map , и вы получите изменяемый хэш.

Я полагаю, что здесь есть множество проблем, но, возможно, Сигилла % не так универсальна, как мне казалось.
3 7

3 ответа:

Вы можете использовать % сигилированные контейнеры для хранения любого значения, которое does Associative роль.

Вы должны быть осторожны, как вы обнаружили, в том, как вы объявляете и назначаете.

В вашем примере, my Pair %pair, вы говорите, чтобы сделать Hash (Не Pair), который может содержать Pair значения (%pair.WHAT = 'Hash[Pair]')

Попробуйте вот что:

my Pair %p2 = mykey => Pair.new: 'a', 'b';

Что может быть приятно. Ограничивая тип значений, вы получите ошибку, если скажете

%p2<c> = 'd';

Поскольку вы не назначаете Pair.

Привязка, как вы также обнаружили, работает так, как вы считаете нужным.

Нам нужно сделать несколько шагов назад, если мы хотим понять, что происходит с вашими примерами:

Переменные привязаны к объектам. По умолчанию сигиллированные переменные изначально привязаны к назначаемым объектам контейнера (Scalar для $ и &, Array для @ и Hash для %).

Если вы добавляете тип к объявлению переменной, например

my Int %var

Или эквивалентно

my %var of Int

Вы устанавливаете ограничение на типы значений, которые может иметь этот контейнер. держать.

Присваивание переменной (=) пытается поместить значение с правой стороны в контейнер, связанный с переменной с левой стороны, что приведет к ошибке, если это ограничение типа не будет выполнено. По умолчанию только переменные & имеют такое ограничение (cf (my &).VAR.of vs (my %).VAR.of).

Напротив, повторная привязка переменной (:=) заменит объект контейнера. Если вы хотите установить ограничения на то, какие типы объектов могут быть связаны, вам нужно is вместо этого, если of:

my %var is Pair;
%var := x => 1; # ok
%var := 42;     # not ok

Сигиллированные переменные подразумевают контраинты типа по умолчанию (нет для $, Callable ибо &, Positional для @ и Associative для %). Обратите внимание, что это ограничение по умолчанию переопределяется явным, например

my %var is Int;
%var := 42; # ok even though 42 is not Associative
Наконец, обратите внимание, что is не просто устанавливает ограничение типа, но также привязывает переменную к вновь созданному экземпляру этого типа:
my %pair is Pair;
say %pair; # (Mu) => (Mu), ie Pair.new()
Я не знаю никакого способа просто сделать первое.

Честно говоря, мне кажется, что это ошибка. % контейнеры не имеют проблем с хранением Pair, который построен с помощью конструктора fat arrow infix:

my %pair = what => 'a pair';
Однако контейнер переопределяет тип, поэтому вы получаете Hash, а не Pair.
%pair.WHAT; #=> (Hash)