
Действительно ли \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
Ответ на ваш вопрос — «еще один», т.е. \item
и \bar
(итого два).
Способ \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'd или \let'd становится чем-то другим внутри группы, старая версия сохраняется (складывается) и восстанавливается в конце группы.
Ни одна из стандартных конструкций не будет генерировать больших потерь «стекового» трафика, если только вы не используете бесконечную рекурсию вложенных групп или что-то подобное.
Можно сгенерировать большое конечное число вложенных групп с различными определениями заданного макроса, но для этого придется проявить некоторую хитрость:
\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}