perl6 rakudo 2016.11 match пытается назначить переменную только для чтения, почему не в 2016.07?

У меня есть следующий метод в классе действий, который хорошо работал в Rakudo 2016.07, но я только что установил 2016.11, и теперь новый Rakudo говорит, что мой метод пытается назначить переменную только для чтения, и я просто не вижу проблемы:

method ptName ($/) { 
    my $nameStr = $/.Str, my $lastName, my $firstName; 
    my $newMatch  # this is line 182; 
                  # Cannot assign to a readonly variable or a value
       = $nameStr.match(/ \" (<alpha>+) .*? \, \s* (<alpha>+) .*? \" /);
    $lastName  = $newMatch[0];
    $firstName = $newMatch[1];
    make "$lastName $firstName"; 
}

Все сообщение об ошибке

Cannot assign to a readonly variable or a value
  in method ptName at /home/lisprog/Binary/grammar.pl line 182
  in regex ptName at /home/lisprog/Binary/grammar.pl line 151
  in regex TOP at /home/lisprog/Binary/grammar.pl line 137
  in block <unit> at /home/lisprog/Binary/grammar.pl line 217

Какая языковая спецификация изменилась? Пожалуйста помоги. Спасибо.

=====================================================

Спасибо райф, Кристоф, ZZ!! Я не знаю, как добавить длинный комментарий с правильным форматированием. Итак, я добавляю комментарии к своему сообщению.

Я написал тестовую программу, и теперь кажется, что если я не использую ($/) в сигнатуре метода, потому что мне нужно использовать .match внутри метода, я больше ничего не смогу сделать. Что я сделал не так? Вот тестовая программа и результаты:

Программа испытаний:

grammar test {
    regex TOP   { <foo><bar> }
    regex foo   { :i \s* foo \s* }
    regex bar   { :i \s  bar \s* }
}

class actTest {
    method foo ($x) { # program fails if I use $/ in signature
      print "1 "; say $x; # how to combine the 2 and show $x as match?
      print "2 "; say $x.WHAT;
      my $newStr = $x.Str;
      print "3 "; say $newStr;
      my $newMatch 
           = $newStr.match(/:i(f)(oo)/); # adverb cannot be outside?
      print "4 "; say $newMatch.WHAT;
      print "5 "; say $newMatch;
      print "6 "; say $/;
      my $oo = $newMatch[1].Str;
      print "10 "; say $oo;
      my $f = $newMatch[0].Str;
      print "11 "; say $f;
      my $result = $oo ~ $f;
      print "12 "; say $result;
      make $result; # now I cannot make anything; huh???
    }
    method TOP ($/) { 
      print "8 "; say $<bar>;
      print "9 "; say $<foo>.made; # failed, method 'foo' makes nothing
      make $<bar> ~ $<foo>.made; 
    }
}

my $m = test.parse("Foo bar", actions => actTest.new);
print "7 "; say $m;

И результаты:

1 「Foo 」
2 (Match)
3 Foo 
4 (Match)
5 「Foo」
 0 => 「F」
 1 => 「oo」
6 「Foo」
 0 => 「F」
 1 => 「oo」
10 oo
11 F
12 ooF
1 「Foo」
2 (Match)
3 Foo
4 (Match)
5 「Foo」
 0 => 「F」
 1 => 「oo」
6 「Foo」
 0 => 「F」
 1 => 「oo」
10 oo
11 F
12 ooF
8 「 bar」
9 (Any)
Use of uninitialized value of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to
something meaningful.
in method TOP at matchTest.pl line 28
7 「Foo bar」
 foo => 「Foo」
 bar => 「 bar」

person lisprogtor    schedule 05.12.2016    source источник
comment
Что-то смутно припоминаю об этом. Что происходит, когда вы пишете method ptName ($/ is copy) {? А как насчет method ptName ($/ is rw) {?   -  person raiph    schedule 06.12.2016
comment
Спасибо райф! Когда я использую ($/ является копией) для любого $a=$someString.match(), программа запускается, но не может дать осмысленные значения $a[0] или $a[1]; когда я использую ($/ is rw), возникает новая ошибка, и в ней говорится, что параметр «$/» ожидал доступный для записи контейнер, но получил значение Match. У меня не было этой проблемы в Rakudo 2016.07. Я думаю, что что-то сломалось в 2016.11. В прошлый раз, когда я пытался сообщить об ошибке, электронное письмо было возвращено как недоставленное. Спасибо.   -  person lisprogtor    schedule 06.12.2016
comment
@lisprogtor: похоже, люди снова могут открывать заявки, см. perl6.fail   -  person Christoph    schedule 06.12.2016
comment
Текущий способ открыть тикеты — отправить электронное письмо по адресу [email protected]. Кнопка «Новый тикет» была отключена из-за массовой рассылки спама, и над этой проблемой все еще работают.   -  person    schedule 06.12.2016


Ответы (4)


Здесь два вопроса, и я отвечу на каждый по очереди:

1) match tries to assign to read-only variable

Он пытается установить $/, который у вас уже есть в вашей области видимости и доступен только для чтения. Вы можете просто использовать другое имя в подписи для файла грамматики $/. Я вижу, вы сразу принуждаете его к Str, так почему бы не позволить подписи сделать это:

method ptName (Str() $nameStr) { ... }

2) why not in 2016.07?

Новое поведение не является ошибкой, и основная команда решила, что текущее поведение желательно (EDIT: на самом деле, при дальнейшем изучении выясняется, что старое поведение было ошибкой, когда .match молчаливо не удалось установить $/, если он был только для чтения).

Таким образом, более важный вопрос заключается в том, почему поведение вообще изменилось?

Хотя есть очевидная цель — сохранить поведение таким же, чтобы пользователи могли на него положиться, нам также нужно улучшать вещи и двигаться вперед. Это работает следующим образом: у нас есть огромный набор тестов, который мы называем Roast. Если в код вносятся изменения, которые нарушают тест, это изменение нельзя внести в текущий язык и его необходимо отложить до следующего выпуска языка (поскольку пользователи могут использовать use v6.c или что-то еще, чтобы по-прежнему вести себя по-старому).

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

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

В настоящее время это относится к методу .match, который вы использовали. Я не уверен, откуда вы узнали об этом, так как в конце сентября я создал выпуск документа указывает на то, что .match не было задокументировано, поэтому тогда его не было в документах, и он ожидал капитального ремонта, над которым работал lizmat, что изменило поведение, которое укусило вас.

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

Здравствуй, ЗЗ

person Community    schedule 06.12.2016
comment
чем было обосновано решение? лично я предпочел старое поведение - person Christoph; 06.12.2016
comment
@ Кристоф, я не участвовал в этом изменении, поэтому не могу точно ответить. Вы можете выполнить поиск по логам канала разработки (это было около октября) или зайдите на на наш канал разработчиков и попытайтесь поймать lizmat++, который сделал вся работа. - person ; 06.12.2016
comment
@Christoph, но, поигравшись с кодом, я вижу, что .match действительно установил $/ еще до изменения, он просто молча сбой, когда $/ был доступен только для чтения, что привело к неожиданному поведению. Так что я бы предположил, что это было просто исправление ошибки, а не изменение поведения. - person ; 06.12.2016
comment
Спасибо ZZ, Кристоф, Раиф!! Теперь, кажется, возникла новая проблема: кажется, что если я не использую ($/) в сигнатуре метода, потому что мне нужно использовать .match внутри метода, я больше ничего не смогу сделать. Что я сделал не так? Пожалуйста, смотрите тестовую программу и результаты в моем исходном посте, который я отредактировал. - person lisprogtor; 07.12.2016
comment
@lisprogtor, make - это просто ярлык для вызова $/.make. Итак, поскольку вы не используете $/, используйте $whatever.make(...) - person ; 08.12.2016

По словам git blame src/core/Str.pm, лизмат работал над этим в октябре. Str.match теперь будет возиться с лексическим $/ вызывающего блока, хотя раньше этого явно не было.

Это означает, что Str.match вернет свой результат дважды: сначала как возвращаемое значение, а второй раз вне диапазона, установив $/. Хотя приложение регулярных выражений через ~~ также делает это (что необходимо, чтобы вы могли использовать синтаксический сахар, такой как $0 или $<foo>), я не уверен, что Str.match должен. Если раньше этого не было, я подозреваю, что это может быть ошибка: либо сообщите об этом, либо спросите об этом в #perl6 на Freenode.

Как указывает Zoffix, это старое поведение было ошибочным, поскольку $/ всегда должен был быть установлен, но невозможность сделать это просто не вызывала исключения.

person Christoph    schedule 05.12.2016
comment
Спасибо Кристоф! Я не уверен, что вы имеете в виду под отсутствием необходимости делать это. - person lisprogtor; 06.12.2016
comment
@lisprogtor: ср say "foo".match(/f/).WHICH === $/.WHICH; Я уточню... - person Christoph; 06.12.2016
comment
FWIW, ~~ также возвращает результирующий объект Match: my $res = 'foo' ~~ /.+/; скажи $res - person ; 06.12.2016
comment
@ZoffixZnet: это действительно так (как и должно быть); Я подумал, что настройка $/ может быть одной из вещей, которая отличает $s ~~ /.../ от $s.match(/.../), помимо того, что одна из них имеет меньше волнистых линий... - person Christoph; 06.12.2016

Я хочу поблагодарить ZZ, Christoph, raifh и smls за помощь. Моя проблема была решена:

  1. используя сигнатуру метода, отличную от $/, и
  2. использование объекта сопоставления подписи для создания вместо использования $/ для создания.

Также см. ответы по адресу: действия грамматики perl6: невозможно ничего сделать, если не используется $/

person lisprogtor    schedule 08.12.2016

Вы также можете использовать сразу вызываемую лямбду: -> $x { my $/; $x.match(/regex/) }($/)

person Solomon Ucko    schedule 23.08.2020