Почему amsmath и \char взаимодействуют таким образом?

Почему amsmath и \char взаимодействуют таким образом?

Я обнаружил это, когда пытался переопределить \char для обозначения характеристики поля и получил странное сообщение об ошибке. Ниже приведен минимальный пример, демонстрирующий странную вещь, которая произошла.

\documentclass[12pt]{article}

\usepackage{amsmath}

\renewcommand{\char}{\stepcounter{section}}

\begin{document}

\section{test}

test$1 + 1 = 2$test$2 + 2 = 4$test

\section{test}

test$1 + 1 = 2$test$2 + 2 = 4$test

\section{test}

\end{document}

Если вы наберете это, вы получите разделы с номерами 1, 3 и 4. Экспериментируя с этим, я определил, что первая встроенная математика, отображение математики или среда выравнивания документа вызывают \char один раз, и с тех пор ничто другое, похоже, не может заставить его вызываться снова. Это происходит ТОЛЬКО если загружен пакет amsmath. Что, черт возьми, происходит? Есть ли способ переопределить \char, не вызывая странных проблем?

решение1

вкратце

Можно ли безопасно переопределить \char? Без этого нетмногоработы, которая окажется бесполезной.

Никогда не делай \renewcommandпо команде, о которой не знаешь. По своей команде делай

\DeclareMathOperator{\Char}{char}

и использовать \Char. Или, может быть \fldchar, выберите имя, которое вы считаете лучшим, нонет \char.

Развернутый ответ

Конкретная ошибка возникает из-за того, что в своем макросе amsmathиспользует , который выполняется каждый раз, когда математическая формула впервые появляется после изменения размера шрифта.\char\resetMathstrut@

\def\resetMathstrut@{%
  \begingroup
  \setbox\z@\hbox{%
    \mathchardef\@tempa\mathcode`\(\relax
    \def\@tempb##1"##2##3{\the\textfont"##3\char"}%
    \expandafter\@tempb\meaning\@tempa \relax
  }%
 \edef\@tempa{%
     \ht\Mathstrutbox@\the\ht\z@\relax
     \dp\Mathstrutbox@\the\dp\z@\relax}%
  \expandafter\endgroup\@tempa
}

На самом деле нет необходимости описывать, что делает этот макрос, за исключением того, что он создает математическую стойку для использования в средах выравнивания.

В вашем коде этот макрос выполняется только один раз, но если вы добавите формулу в аргумент, то \sectionувидите, что он выполняется еще один раз.

Есть ли способ безопасно переопределить \char? Да, есть: создайте собственную копию всего дерева LaTeX, добавьте \let\primitivechar\charв начало (копию) latex.ltx; затем замените все остальные вхождения \charво всем дереве на \primitivechar. Затем перекомпилируйте форматы. Никогда не знаешь, какой пакет может использовать \char.

Серия ack(или grep) говорит, что \charвстречается 8682 раза в 960 файлах:

> ack -ch '\\char[^a-z]' /usr/local/texlive/2022/texmf-dist/tex/latex/
8682
> ack -cl '\\char' /usr/local/texlive/2022/texmf-dist/tex/latex/ | wc -l
960

Однако учтите, что никто, кроме вас, не сможет запустить LaTeX в вашем документе. Поэтому ответ на ваш вопрос:

Да, но с практической точки зрения — нет.

Некоторая предыстория. Одной из первоначальных целей LaTeX3 былоне определитькаждый примитив, заменив их псевдонимами. Однако команда поняла, что это непрактично, поскольку это означало бы, что по сути ни один текущий пакет не может быть использован с новой версией, а их тысячи!

Почему оригинальный LaTeX не делал этого шага? По разным причинам, вот основные из них:

  1. На момент написания LaTeX единственным доступным форматом был простой TeX, и LaTeX заимствовал несколько простых конструкций;

  2. переход с простого формата на LaTeX будет проще, что позволит повторно использовать код;

  3. Памяти компьютера было мало;Действительноскудный.

Когда был выпущен LaTeX2e, это могло бы стать поводом для продолжения проекта по присвоению псевдонимов всем примитивам и замене их псевдонимами, поскольку пакетов было не так много. Но LaTeX не работал бы практически ни на одной машине, поскольку каждый псевдоним занимает место в памяти. В настоящее время такие соображения по памяти не являются проблемой, но пакеты исчисляются тысячами.

В некоторых случаях можно переопределить примитив, но только для того, чтобы немного изменить его поведение: \inputнапример, LaTeX делает это с помощью , но переопределение \inputвсегда в конечном итоге будет вызывать псевдоним примитива.

решение2

\charявляется примитивом TeX для доступа к символу по номеру, поэтому его переопределение сломает все виды конструкций Latex, а не толькоamsmath

\documentclass{article}

\renewcommand{\char}{\stepcounter{section}}


\begin{document}

\begin{picture}(0,0)
\put(0,0){\circle{5}}
\end{picture}
\end{document}

LaTeX не может выбрать круг нужного размера.

Всегда используйте \newcommand, чтобы избежать случайных переопределений. Используйте только \renewcommandтогда, когда хотите изменить поведение всех использований существующей команды.

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