% 暫定
このセクションは、価値が疑わしい、または収録するにはニッチすぎる可能性があるパターンや技法のためのものです。
そろばんカウンター
暫定: より説得力のある例が必要です。
Ook!マクロの重要な部分ではあるものの、Rust のグループで示されていないネストしたグループにマッチすることは十分に珍しく、収録に値しない可能性があります。
注記: このセクションでは、プッシュダウン蓄積とインクリメンタル TT muncherを理解していることを前提としています。
macro_rules! abacus { ((- $($moves:tt)*) -> (+ $($count:tt)*)) => { abacus!(($($moves)*) -> ($($count)*)) }; ((- $($moves:tt)*) -> ($($count:tt)*)) => { abacus!(($($moves)*) -> (- $($count)*)) }; ((+ $($moves:tt)*) -> (- $($count:tt)*)) => { abacus!(($($moves)*) -> ($($count)*)) }; ((+ $($moves:tt)*) -> ($($count:tt)*)) => { abacus!(($($moves)*) -> (+ $($count)*)) }; // 最終結果がゼロかどうかを確認する。 (() -> ()) => { true }; (() -> ($($count:tt)+)) => { false }; } fn main() { let equals_zero = abacus!((++-+-+++--++---++----+) -> ()); assert_eq!(equals_zero, true); }
この技法は、ゼロまたはゼロ付近から始まり、次の操作をサポートしなければならない可変のカウンターを追跡する必要がある場合に使用できます。
- 1 増やす。
- 1 減らす。
- ゼロ(または他の任意の固定された有限値)と比較する。
値 n は、グループ内に格納された特定のトークンの n 個のインスタンスで表されます。変更は再帰とプッシュダウン蓄積を使用して行います。使用するトークンが x であると仮定すると、上記の操作は次のように実装されます。
- 1 増やす:
($($count:tt)*)にマッチし、(x $($count)*)に置換する。 - 1 減らす:
(x $($count:tt)*)にマッチし、($($count)*)に置換する。 - ゼロと比較する:
()にマッチする。 - 1 と比較する:
(x)にマッチする。 - 2 と比較する:
(x x)にマッチする。 - (以下同様...)
このように、カウンターに対する操作は、そろばんのようにトークンを前後にはじくようなものです。1
負の値を表したい場合、-n は別のトークンの n 個のインスタンスとして表すことができます。上の例では、+n は n 個の + トークンとして格納され、-m は m 個の - トークンとして格納されます。
この場合、操作は少し複雑になります。カウンターが負の場合、インクリメントとデクリメントは実質的に通常の意味が逆になります。つまり、正と負のトークンとしてそれぞれ + と - を用いる場合、操作は次のように変わります。
- 1 増やす:
()にマッチし、(+)に置換する。(- $($count:tt)*)にマッチし、($($count)*)に置換する。($($count:tt)+)にマッチし、(+ $($count)+)に置換する。
- 1 減らす:
()にマッチし、(-)に置換する。(+ $($count:tt)*)にマッチし、($($count)*)に置換する。($($count:tt)+)にマッチし、(- $($count)+)に置換する。
- 0 と比較する:
()にマッチする。 - +1 と比較する:
(+)にマッチする。 - -1 と比較する:
(-)にマッチする。 - +2 と比較する:
(++)にマッチする。 - -2 と比較する:
(--)にマッチする。 - (以下同様...)
先頭の例では、いくつかのルールをまとめていることに注意してください(たとえば、() に対するインクリメントと ($($count:tt)+) に対するインクリメントを、($($count:tt)*) に対するインクリメントにまとめています)。
カウンターの実際の値を取り出したい場合は、通常のカウンターマクロを使用して行えます。上の例では、終端ルールを次のように置き換えることができます。
macro_rules! abacus {
// ...
// カウンターを整数式として抽出する。
(() -> ()) => {0};
(() -> (- $($count:tt)*)) => {
{(-1i32) $(- replace_expr!($count 1i32))*}
};
(() -> (+ $($count:tt)*)) => {
{(1i32) $(+ replace_expr!($count 1i32))*}
};
}
macro_rules! replace_expr {
($_t:tt $sub:expr) => {$sub};
}
JFTE: 厳密に言えば、上記の
abacus!の定式化は不必要に複雑です。マクロ内でカウンターの値に対してマッチする必要がないのであれば、繰り返しを使用してはるかに効率的に実装できます。macro_rules! abacus { (-) => {-1}; (+) => {1}; ($($moves:tt)*) => { 0 $(+ abacus!($moves))* } }