TL; DR$<nr>正規表現の評価後まで評価を延期します。@ JoKing ++は1つの方法を提案します。もう1つは、置換を中括弧({$<nr>})で囲むだけです。
元のコードが呼び出されるとどうなるか subst
Rakuはsubstルーチンを呼び出す前に、それに渡す引数のリストをまとめます。
2つの値があります。最初は正規表現です。それはないではない実行します。2番目の値は$<nr>です。これNilは、プログラムの開始時に、現在の一致オブジェクト変数がその値を主張する何かにバインドされており、そのNil中のキーの値にアクセスしようとすると$<nr>-も返されるため、評価されますNil。したがって、この時点で、substこれまでに実行される前に、事態はすでにうまくいっていません。
Rakuがこの引数のリストを組み立てると、を呼び出そうとしますsubst。成功してsubst実行されます。
次の一致を取得するにsubstは、正規表現を実行します。これにより、現在の一致オブジェクト変数が更新されます$/。ただし、すでにに渡された置換値に変更を加えるには遅すぎsubstます。
一致が得られたら、subst次に置換引数を調べます。それはそれを見つけ、それにNil応じて行動します。
の2番目の呼び出しではsubst、$<nr>はの最初の呼び出しから値を取得しましたsubst。等々。
の評価を延期する2つの方法 $<nr>
@JoKingはの使用を検討することを提案していますS///。この構成では、最初に(最初の/sのペアの間)正規表現を評価し、次に置換(最後の/sのペアの間)を評価します。(のSような他の有効な構文を使用する場合も同じ原則が適用されますS[...] = ...。)
を使用する場合subst、前のセクションで説明したように、Rakuはそれを呼び出す前に引数リストをまとめます。正規表現(実行されない)とクロージャー(実行されない)を検出します。次にsubst、それらの引数を使用して呼び出しを試み、成功します。
次に、subst実行を開始します。一致(正規表現)と置換(クロージャー)の両方のコードを受け取りました。
マッチング操作として正規表現を実行します。正規表現が一致を返した場合、substクロージャーを実行し、返された値を置換として使用します。
したがって、$<nr>ネイキッド値として渡すことからにフリーズすることを意味Nilするクロージャーに渡すことに切り替えたため、値$/が入力済みの<nr>エントリとの一致に設定されるまで評価が延期されたため、問題を解決しました。
これが機能するのは、ユーザーが望めば、設計/実装された人substが、一致引数と置換引数の両方をCode(一致の正規表現と置換の通常のクロージャ)の形式にするのに十分なほどスマートで素晴らしいためです。次に、最初に一致を実行し、最後の置換として後者の呼び出しの結果を使用して、置換クロージャーが渡された場合にのみ、それを実行します。同様にS///機能します。これは、置換が最初に評価された後にのみ置換を評価するように設計されているためです。