«Невозможно присвоить неизменное значение» при попытке присвоить строку + роль - PullRequest
0 голосов
/ 29 мая 2018

Начиная с пример на странице документа Iterable

role DNA does Iterable {
  method iterator(){ self.comb.iterator }
};

my @a does DNA = 'GAATCC';
.say for @a; # OUTPUT: «G␤A␤A␤T␤C␤C␤» 

Мне показалось странным, что он объявлен с использованием @, поэтому я изменил его на natural способ объявления строк, $:

my $a does DNA = 'GAATCC';

Но это терпит неудачу с несколько изумительным «Невозможно присвоить неизменное значение».Нет необходимости назначать на месте, поэтому мы можем сделать:

my $a = 'GAATCC';
$a does DNA;
.say for $a;

, который просто оставляет замешательство на потом.Но это просто печатает строку, не обращая никакого внимания на Iterable mixin.Затем назовем его явно:

.say for $a.iterator;

он делает то же самое, что и раньше, только печатает значение $a.iterator, фактически не вызывая функцию:

<anon|69>.new

Thisвыглядит как то же самое, что происходит в этом другом вопросе .Исходный вопрос: я не понимаю, какую роль на самом деле играет Iterable, и что на самом деле делает for и когда он вызывает iterator для какого-либо объекта.Есть идеи?

Ответы [ 2 ]

0 голосов
/ 30 мая 2018

Заголовок вашего вопроса указывает на ошибку.Этот ответ покрывает ошибку, а также другие неявные и явные вопросы, которые вы задали.

Фон

терпит неудачу с некоторым изумлением: «Невозможно присвоить неизменное значение».

Я думаю, что это ошибка.Давайте начнем с некоторого кода, который работает:

my $a = 42;
say $a;          # 42
say WHAT $a;     # (Int)               type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar)            type of VARIABLE currently BOUND to $a
$a = 42;         # works fine

В объявлении my 1013 * связывается с новым Scalar контейнером .Контейнер Scalar обычно скрывается.Если вы спросите WHAT type $a is, вы на самом деле получите тип значения, в настоящее время присвоенного скаляру (значение, которое оно «содержит»).Вам нужно VAR, чтобы получить доступ к контейнеру BOUND до $ a.Когда вы присваиваете = контейнеру Scalar, вы копируете присвоенное значение в контейнер.

role foo {}
$a does foo;     # changes the VALUE currently ASSIGNED to $a
                 # (NOT the VARIABLE that is BOUND to $a)
say $a;          # 42                  mixed in `foo` role is invisible
say WHAT $a;     # (Int+{foo})         type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar)            type of VARIABLE currently BOUND to $a
$a = 99; say $a; # 99

does смешивает роль foo в 42.Вы все еще можете присвоить $ a, потому что он все еще привязан к Scalar.

Обратите внимание, как эти два использования does имеют очень разные эффекты:

my $a does foo;  # mixes `foo` into VARIABLE bound to $a
$a does foo;     # mixes `foo` into VALUE assigned to $a

Ошибка

$a.VAR does foo; # changes VARIABLE currently BOUND to $a (and it loses the 42)
say $a;          # Scalar+{foo}.new    VALUE currently ASSIGNED to $a
say WHAT $a;     # (Scalar+{foo})      type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar+{foo})      type of VARIABLE currently BOUND to $a

$a = 'uhoh';     # Cannot assign to an immutable value

does смешивает роль foo с Scalar, привязанным к $ a.Кажется, что Scalar с миксином больше не работает как контейнер, и назначение не выполняется.

В настоящее время это выглядит как ошибка.

my $b does foo;  # BINDS mixed in VARIABLE to $b
$b = 'uhoh';     # Cannot assign to an immutable value

my $b does foo имееттот же результат, что и my $b; $b.VAR does foo;, так что вы получите ту же проблему, что и выше.

Другие вещи, которые вас смущают

my $a = 'GAATCC';
$a does DNA;
.say for $a;

, просто печатает строку, не обращая никакого внимания наIterable mixin.

Поскольку $a VARIABLE по-прежнему привязан к Scalar (как объяснено в разделе Background выше), VALUE, который теперь имеетDNA смешанная роль не имеет значения для процесса принятия решения for, который используется для вызова метода .iterator его аргумента .

Давайте назовем его тогда явно ...печатает значение $a.iterator без фактического вызова функции:

.say for $a.iterator;

Ну, это действительно вызывает метод DNA вашей роли *1081*.Но у этого есть еще один .iterator вызов в конце self.comb, возвращенного методом iterator вашей роли DNA, так что вы .say используете этот вторичный .iterator.

Решения, которые работают сегодня

Я думаю, что ответ Брэда хорошо охватывает большинство ваших вариантов.

И я думаю, что ваша хорошая does DNA сущность так же хороша, как и онас сегодняшним P6, если вы хотите использовать $ sigil.

Решение, которое может однажды сработать

В идеальном мире вся прелесть в дизайне P6 будет полностью реализована в6.c и реализация компилятора Rakudo в Perl 6. Возможно, это будет включать возможность написать это и получить то, что вы хотите:

class DNA is Scalar does Iterable { ... }
my $a is DNA = 'GAATCC';
.say for $a;

Код ... будет примерно таким же, как у васв вашей сути, за исключением того, что класс DNA будет скалярным контейнером, и поэтому вместо метода new будет использоваться метод STORE или аналогичный, который назначит переданное значение атрибуту $!value или некоторому такому, когдазначение было присвоено контейнеруиспользуя =.

Но вместо этого вы получаете:

is trait on $-sigil variable not yet implemented. Sorry.

Таким образом, наиболее близким сегодня к идеалу = 'string' для изменения $a является привязка с помощью := DNA.new('string') как вы делали в своей сути.

Обратите внимание, что вы можете связывать произвольные составные контейнеры с @ и % переменными сигил.Таким образом, вы можете видеть, как все в конечном итоге должно работать.

0 голосов
/ 29 мая 2018

Я не думаю, что эта строка делает то, что вы думаете:

my @a does DNA = 'GAATCC';

Это то же самое, что:

my @a := [ 'GAATCC', ];
@a does DNA;

По сути, вызов .comb приводит массивв Str и разбивает его на символы.


Если вы вместо этого сделали это:

my @a = 'GAATCC' but DNA;

Что в основном совпадает с

my @a := Seq.new(('GAATCC' but DNA).iterator).Array;

Примечаниечто @ переменные хранят Positional значения, а не Iterable значения.


То, что вы хотите, это

my $a = 'GAATCC' but DNA;

$a.map: &say;

Если вы хотите иметь возможность использоватьfor вы не можете использовать переменную с $ sigil

my \a = 'GAATCC' but DNA;

.say for a;

Возможно, вы захотите добавить Seq list List и т. Д. К DNA.

role DNA does Iterable {
  method iterator(){
    self.comb.iterator
  }
  method Seq(){
    Seq.new: self.iterator
  }
  method list(){
    # self.Seq.list
    List.from-iterator: self.iterator
  }
}

my $a = 'GAATCC' but DNA;
.say for @$a;
...