
Я сталкивался с явно идиоматическим использованием термина во \pgf@marshal
всем пакете PGF и мне интересно, почему он используется.
Например из pgflibraryshapes.gates.logic.US.code.tex
:
{%
\edef\pgf@marshal{%
\noexpand\pgfpatharc{90}{-90}{\the\pgf@yc}%
}%
\pgf@marshal%
}
Это, вероятно, легко, но почему бы просто не
\pgfpatharc{90}{-90}{\the\pgf@yc}
?
решение1
Пока \pgfpatharc
не используется \pgf@yc
(по крайней мере, пока он не будет оценен и сохранен где-то еще), и это было бы безопасно сделать
\pgfpatharc{90}{-90}{\pgf@yc}
(без \the
четного),само руководство предупреждает
Внимание:PGF использует эти регистры для выполнения операций пути. По соображениям эффективности команды пути не всегда их охраняют. Как следствие, код
\pgfpointadd{\pgfpoint{\pgf@xa}{\pgf@ya}}{\pgfpoint{\pgf@xb}{\pgf@yb}}
может потерпеть неудачу: Внутри
\pgfpointadd
регистры\pgf@xa
и друзья могут быть изменены. В частности, может случиться так, что\pgf@xb
is изменяется до того, как\pgfpoint{\pgf@xb}{\pgf@yb}
is вычисляется. Правильным решением было бы сначала развернуть все using\edef
и обработать значения впоследствии, что приведет к ненужным дорогостоящим операциям. Конечно, этого можно избежать, просто заглянув в исходный код и\pgfpointadd
увидев, какие регистры используются.
(Довольно интересно, что данный пример действительно будет работать, но не
\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@yb}}{\pgfpoint{\pgf@xa}{\pgf@ya}}
(Поскольку координаты первой точки будут сохранены \pgf@xa
и \pgf@ya
позднее добавлены к координатам второй точки.)
В случае \pgfpatharc
get #3
вычисляется до того, как \pgf@yc
будет использован, и это происходит только в определенной области, поэтому \pgf@yc
после него значение остается прежним \pgfpatharc
.
Так что да, разработчик библиотеки схем мог бы взглянуть на определение \pgfpatharc
и решить, что в этом нет смысла.
Но есть и другие моменты, которые следует учитывать:
\pgfpatharc
На момент написания библиотеки схем команда могла работать иначе .\pgfpatharc
В будущем команда может измениться .- Автор библиотеки схем в какой-то момент заметил конфликт и изменил все подобные макровызовы, чтобы больше никогда не сталкиваться с подобными проблемами.
решение2
Еще одна точка зрения для тех, кто не очень хорошо знаком с моделью исполнения TeX.
Викисловарь:
marshal (глагол)
4. Собирать данные для передачи.
5. (вычислительный, переходный) Сериализовать объект в упорядоченное состояние, представленное последовательностью байтов, которое впоследствии может быть преобразовано обратно в объект с эквивалентными свойствами.
Хотя в вычислительном контексте обычно желательно значение 5, в данном случае значение 4 представляется более релевантным. Но его также можно понимать как «сериализовать код в список токенов, а затем выполнить список токенов как код» --- но тогда в TeX код и список токенов — это в основном одно и то же.
вкратце:
По умолчанию команды TeX выполняются «извне внутрь» — то есть, в отличие от типичных языков программирования, где «аргументы функции» «оцениваются» перед «передачей в функцию», в TeX аргумент передается макросу дословно.
- в Python
f(1+2)
иf(3)
идентичен, поскольку1+2
вычисляется до3
того, какf
получает его. В TeX\f{\numexpr 1+2\relax}
и\f{3}
не идентичен.
- в Python
В этом случае, как поясняется вдругой ответ, вызывающая сторона хочет оценить число заранее, перед передачей функции.
TeX имеет очень ограниченное количество механизмов для манипулирования токенами. Код, который вы видите, эквивалентен чему-то вроде
eval(r"\pgfpatharc{90}{-90}{" + pgfyc + "}")
в синтаксисе Python --- код обрабатывается как список токенов, а затем выполняется.
Альтернативой было бы добавлять
\expandafter
везде в коде, что определенно менее эффективно. (Есть также\expanded{\unexpanded{...}}
, но на момент написания кода его не существовало.)Другие места, где используется эта идиома, можно увидеть, например, здесь:как использовать
pgfplots
сюжет в циклес\edef\temp{...}\temp
.Префикс
pgf@
означает, что имя макроса является внутренним для пакета pgf. Если вы не редактируете исходный код PGF/TikZ, вам следует создать собственное имя и не использовать повторно\pgf@marshal
.