Идиоматическое использование \pgf@marshal в PGF

Идиоматическое использование \pgf@marshal в PGF

Я сталкивался с явно идиоматическим использованием термина во \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@xbis изменяется до того, как \pgfpoint{\pgf@xb}{\pgf@yb}is вычисляется. Правильным решением было бы сначала развернуть все using \edefи обработать значения впоследствии, что приведет к ненужным дорогостоящим операциям. Конечно, этого можно избежать, просто заглянув в исходный код и \pgfpointaddувидев, какие регистры используются.

(Довольно интересно, что данный пример действительно будет работать, но не

\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@yb}}{\pgfpoint{\pgf@xa}{\pgf@ya}}

(Поскольку координаты первой точки будут сохранены \pgf@xaи \pgf@yaпозднее добавлены к координатам второй точки.)

В случае \pgfpatharcget #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}не идентичен.
  • В этом случае, как поясняется вдругой ответ, вызывающая сторона хочет оценить число заранее, перед передачей функции.

  • TeX имеет очень ограниченное количество механизмов для манипулирования токенами. Код, который вы видите, эквивалентен чему-то вроде

    eval(r"\pgfpatharc{90}{-90}{" + pgfyc + "}")
    

    в синтаксисе Python --- код обрабатывается как список токенов, а затем выполняется.

    Альтернативой было бы добавлять \expandafterвезде в коде, что определенно менее эффективно. (Есть также \expanded{\unexpanded{...}}, но на момент написания кода его не существовало.)

  • Другие места, где используется эта идиома, можно увидеть, например, здесь:как использовать pgfplotsсюжет в циклес \edef\temp{...}\temp.

  • Префикс pgf@означает, что имя макроса является внутренним для пакета pgf. Если вы не редактируете исходный код PGF/TikZ, вам следует создать собственное имя и не использовать повторно \pgf@marshal.

Связанный контент