Замена строки на .subst в цикле for

Я хотел бы сделать замену строки в блоке for, используя именованный захват. Я ожидал получить числа 1,2,3 в качестве вывода. Но это Nil для первого запуска, а затем 1 и 2 для 2-го и 3-го запуска. Как правильно использовать .subst в конструкции цикла? Я вижу такое же поведение при использовании конструкции map вместо цикла for. Это работает, как и ожидалось, если я заменяю фиксированным строковым значением.

for <a1 b2 c3> -> $var {
    say $var;
    say $var.subst(/.$<nr>=(\d)/, $<nr>); #.subst(/.$<nr>=(\d)/, 'X'); #OK      
}

#`[
This is Rakudo version 2019.11 built on MoarVM version 2019.11   
Output:

a1
Use of Nil in string context
  in block  at test3.pl6 line 3

b2
1
c3
2
]

person Valle Lukas    schedule 22.01.2020    source источник
comment
Мне интересно. Что такое $‹nr› ? (Я не смог найти его в документации по raku.)   -  person p6steve    schedule 29.01.2020
comment
@p6steve именованный захват   -  person Valle Lukas    schedule 29.01.2020
comment
docs.raku.org/language/ - спасибо @valle - сейчас нашел!   -  person p6steve    schedule 29.01.2020
comment
Возможно, стоит иногда использовать S///. В этом случае вы можете сделать S[.$<nr>=(\d)] = $<nr> given $var   -  person Jo King    schedule 30.01.2020
comment
@JoKing Хорошо. Я проголосовал за ваш комментарий, затем отменил голосование, потому что понял, что хочу кое-что проверить (что оказалось неважным), и теперь SO не позволит мне восстановить мой голос. Поэтому я пишу это, чтобы вручную добавить +1 к вашему хорошему предложению. Я также включил это в свой ответ.   -  person raiph    schedule 30.01.2020


Ответы (1)


TL;DR Отложите оценку $<nr> до завершения оценки регулярного выражения. @JoKing++ предлагает один способ. Другой вариант — просто заключить замену в фигурные скобки ({$<nr>}).

Что происходит, когда исходный код вызывает subst

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

Есть два значения. Первый — это регулярное выражение. Он не запускается. Второе значение $<nr>. Он оценивается как Nil, потому что в начале программы текущая переменная объекта сопоставления связана с чем-то, что утверждает, что ее значение равно Nil, и любая попытка получить доступ к значению ключа в нем — $<nr> — также возвращает Nil. Так что к этому моменту все уже пошло не так, еще до того, как subst запустится.

Как только Raku соберет этот список аргументов, он попытается вызвать subst. Это удается, и subst запускается.

Чтобы получить следующее совпадение, subst запускает регулярное выражение. Это обновляет текущую переменную объекта соответствия $/. Но уже слишком поздно что-либо менять в значении подстановки, которое уже было передано в subst.

Имея на руках совпадение, subst затем просматривает аргумент подстановки. Он находит его Nil и действует соответственно.

Для второго вызова subst $<nr> принимает значение из первого вызова subst. И так далее.

Два способа отложить оценку $<nr>

@JoKing предлагает рассмотреть возможность использования S///. Эта конструкция сначала оценивает регулярное выражение (между первой парой /s), а затем замену (между последней парой /s). (Тот же принцип применяется, если вы используете другой допустимый синтаксис S, такой как S[...] = ....)

Если вы используете subst, то, как объяснялось в предыдущем разделе, Raku составляет для него список аргументов перед его вызовом. Он находит регулярное выражение (которое не запускается) и замыкание (которое тоже не запускается). Затем он пытается вызвать subst с этими аргументами и преуспевает в этом.

Далее запускается subst. Он получил код как для совпадения (регулярное выражение), так и для замены (замыкание).

Он запускает регулярное выражение как операцию сопоставления. Если регулярное выражение возвращает совпадение, то subst запускает замыкание и использует возвращаемое значение в качестве подстановки.

Таким образом, поскольку мы перешли от передачи $<nr> в качестве голого значения, что означало, что оно было заморожено в Nil, к передаче его в замыкании, которое откладывало его оценку до тех пор, пока $/ не будет установлено в соответствии с заполненной записью <nr>, мы решили проблему. проблема.

Обратите внимание, что это работает только потому, что тот, кто спроектировал/реализовал subst, был достаточно умен/хорош, чтобы позволить аргументам соответствия и подстановки быть формами Code (регулярное выражение для совпадения и обычное закрытие для подстановки), если пользователь этого хочет. Затем сначала выполняется match и только затем выполняется закрытие подстановки, если оно было передано, используя результат этого последнего вызова в качестве окончательного замена. Точно так же работает S///, потому что это было разработано для оценки замены только после того, как она впервые оценила замену.

person raiph    schedule 22.01.2020