
本当に新しい制御シーケンスを作成するのでしょうか\let
、それとも既に定義されている制御シーケンスへのポインターを割り当てるだけでしょうか?
クヌースはこう言う。
let\cs=<token>
\cs
トークンの現在の意味を 示します。 が<token>
別の制御シーケンスである場合、\cs
はその制御シーケンスと同じ意味を持ちます。 (TeXbook 206)
が の別名bars
である新しいリスト環境を定義するとします。\bar
\item
\newenvironment{bars}
{\begin{enumerate}\let\bar\item}
{\end{enumerate}}
そして、次のようにその環境をドキュメント内で 1000 回使用します。
\begin{bars}
\bar bla bla
\bar bla bla bla
\end{bars}
ドキュメントをコンパイルしたときと同じコンテンツがメモリ内の何箇所に存在するでしょうか\item
? 1、2、それとも 1001 でしょうか?
答え1
あなたの質問に対する答えは「あと 1 つ」、つまり、\item
および\bar
(つまり、合計 2 つ) です。
の仕組み\let\a<token>
は、文字通り の意味を<token>
制御シーケンス にコピーすることで\a
、\a
が「実行」されるたびに、 が<token>
そこにあったかのように動作します。このコピーは命令の実行時に行われる\let
ため、 を何度\a
使用しても新しい変更は行われません。さらに、<token>
が変更された場合、そのの意味は(たとえば、別の を通じて\let
)変化しても、 の意味は\a
影響を受けません。
「ポインタ」という用語の使用はある意味では不適切です。なぜなら、言語としてのTeXにはメモリモデルがなく、また、それが実装されている言語には(必ずしも)ランダムアクセスがないからです。そのメモリモデルは、その実装の内部の詳細もその動作を理解する上で重要ではありません。しかし、TeXが(例えば)Cで実装されていると仮定しても、トークンへのポインタの類似物は
\def\a{<token>}
*\a = <token>
これは、 が有効なC構文であると仮定すると、のようになります。この架空の構文*\a = *<token>
は に対応します\let\a<token>
が、構文 は*\a = <token>
最初の構文に似ていますが、実際には を定義する\a
ため、次のようにします。\def\a{<other token>}
と再定義する <token>
これは TeX では不可能です。つまり、TeX にはポインターに正確に類似するものは存在しません。
答え2
TeX は、{} グループにローカルな特定のマクロの複数のバージョンを保存できますが、グループを離れるとメモリが回収され再利用されるため、メモリがいっぱいになることは通常非常に困難です (これが私の最初のコメントの根拠でした)。itemize などのほとんどの環境には、このようなグループ化が含まれています。既存のコマンドがグループ内で別のものに \def または \let されると、古いバージョンが保存 (スタック) され、グループの最後に復元されます。
ネストされたグループの無限再帰などを管理しない限り、標準的な構造では「スタック」の無駄があまり発生しません。
特定のマクロの異なる定義を持つ、有限数のネストされたグループを生成することは可能ですが、少し工夫が必要です。
\documentclass[a5paper,12pt]{article}
\usepackage[margin=20mm]{geometry}
%% version of plain TeX \loop that uses global macros
\def\gloop#1\repeat{\gdef\body{#1}\giterate}
\def\giterate{\body \global\let\next\giterate \else\global\let\next\relax\fi \next}
\let\repeat=\fi % this makes \loop...\if...\repeat skippable
\begin{document}
\raggedright
\section*{Ascending}
\newcount\n
\global\n=0
\gloop
\ifnum \n<100
\bgroup
\edef\foo{\the\n}
\let\baz=\foo
\global\let\foobar=\baz
$\foo^{\baz}_{\foobar} \uparrow$
\global\advance\n 1
\repeat
\section*{Descending}
\global\n=0
\gloop
\ifnum \n<100
$\foo^{\baz}_{\foobar} \downarrow$
\egroup
\global\advance\n 1
\repeat
\end{document}