Понимание \@firstofone

Понимание \@firstofone

Я просматривал этот ответ и пытался понять код, я супер новичок (мой второй день) в LaTeX и я застрял на следующей части кода, которую я не мог заставить работать в не табличной среде. Вот простейшая форма того, что я не понимаю.

\documentclass{article}
\begin{document}
    \newcommand*\f[3]{#1-#2-#3}
    \newcommand*\ex[1]{\f#1 - \expandafter\f\@firstofone}
     Try \ex{111}{221}
\end{document}

По какой-то причине, которая мне не ясна, в связанном коде последний аргумент не потребляется, а остается для потребления конструкцией expandafter\f\.... Насколько я понимаю, \expandafterсначала следует "запустить" \@firstofone, получить {221}аргумент, убрать скобки и передать его \f. Этого не происходит, и я не могу понять, почему.

решение1

Вам нужно использовать, \makeatletterчтобы это сработало, но это самое меньшее.

Сначала вызов \ex{111}{221}расширяется до

\f 111 - \expandafter\f\@firstofone{221}

Теперь \fон развернут и ищет три аргумента, находя 1, 1и 1, поскольку TeX использует один токен, если отсутствует фигурная скобка.

По определению \fэто расширяется и заменяющий текст повторно вставляется во входной поток:

1-1-1 - \expandafter\f\@firstofone{221}

Токены 1-1-1 -не расширяются, поэтому они отправляются на следующий этап. Теперь остается

\expandafter\f\@firstofone{221}

Это отложит \fи расширит \@firstofone, что просто вернет его (аргумент без скобок), поэтому мы получаем

\f221

что становится 2-2-1. Таким образом, чистый эффект вашего кода заключается в печати

1-1-1 - 2-2-1

что не кажется действительно полезным. Где бы вы его ни нашли, не доверяйте ему.

решение2

Как указал egreg в своем ответе, использование \@firstofoneне очень полезно и не имеет значения в данном конкретном случае. Однако есть случаи, когда этоявляетсяполезно. Для полноты картины я хотел бы привести два примера.

Расширяемые макросы

ВПочему именно эта \expandafter\@firstoftwoидиома?Приведен типичный пример использования \@firstoftwoи в полностью расширяемых макросах. , своего рода «функция идентичности» LaTeX, полезна в подобных контекстах, где необходимо обрабатывать только один параметр:\@secondoftwo\@firstofone

\def\gobbleIfZero#1{%
  \ifnum#1=0
    \expandafter\@gobble
  \else
    \expandafter\@firstofone
  \fi
}

foo\gobbleIfZero{0}{bar}

foo\gobbleIfZero{123}{bar}

дам

фу

фубар

\@gobble(как и \@firstofone) принимает один параметр, но отбрасывает его и расширяет до «ничего».

Исправление кошачьих кодов

Немного сложнее, но и интереснее случай, когда задействованы изменения catcode. Когда TeX анализирует аргументы для макросов, он исправляет catcodes всякий раз, когда считывается текст аргумента. Это не имеет значения в вашем случае, поскольку здесь нет никаких изменений catcodes. Но предположим, что приведен следующий, несколько надуманный пример:

\begingroup
\catcode`4=\active
\gdef 4{four}
\endgroup

\newcommand*\f{\catcode`4=\active}
\newcommand*\exA{\f}
\newcommand*\exB{\expandafter\f\@firstofone}

{\exA{345}--{345}}

{\exB{345}--{345}}

Это приводит к

3четыре5-3четыре5

345-3четыре5

Первые четыре строки определяют глобальный макрос, 4который расширяется до four. Обычно4 имеет код 12 (другой), поэтому мы меняем его на 13 (активный), чтобы иметь возможность сделать из него макрос. \fздесь возвращает этот макрос в область действия при выполнении.

При \exAвыполнении код кота 4изменяется на 13, что впоследствии делает4 его расширенным fourв обеих следующих двух группах. Здесь вообще нет параметров, так что это просто.

С другой стороны, в\exB{345} макросе обрабатывается первая часть \@firstofone, которая просто возвращает тот же текст,но исправляет котокодиз4 до 12. После исправления его больше нельзя изменить! Даже если изменение кода кота \fобработанодопервый 345, это не окажет на него никакого влияния. Поскольку catcodes второго {345}еще не были исправлены, изменения все равно будут применяться к этой группе.

Такое поведение весьма удобно, если вы хотите внедрить дополнительный код в существующие макросы, которые обрабатывают изменения catcode, например:\verb (вдохновленоэта жемчужина TeX):

\begingroup
\catcode`\/\active
\catcode`\_\active
\@firstofone{%
  \verb|%
  \catcode`\/\active \def/{\par}%
  \catcode`\_\active \def_#1_{\textcolor{blue}{#1}}%
}_\documentclass_{article}/_\begin_{document}/  We all love _\LaTeX_!/_\end_{document}|
\endgroup

который выводит

выход

Не знаю, где вы об этом \@firstofoneизначально прочитали, но, возможно, это было в одном из таких контекстов.

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