
На основе альтернативного решения egreg для моегопредыдущий вопросиз которого я почерпнул идею превращения символов в макросы, теперь я определил другой синтаксис для скобок, который мне нравится даже больше. Мой макроспочтиработает (хотя здесь есть немного программирования карго-культа, потому что я скопировал некоторую часть его решения, которую не до конца понял — две строки, начинающиеся с \begingroup\lccode
— в свой макрос и немного адаптировал их; я подозреваю, что проблема именно там, потому что остальное, как мне кажется, я понимаю достаточно хорошо, благодаря объяснениям egregs к другому вопросу).
Вот мое определение макроса:
\newcommand{\braket}[2][\middle]{\ensuremath{
\begingroup
\begingroup\lccode`~=`<
\lowercase{\endgroup\def~}{#1\langle}
\begingroup\lccode`~=`|
\lowercase{\endgroup\def~}{#1\pipedel}
\begingroup\lccode`~=`>
\lowercase{\endgroup\def~}{#1\rangle}
\edef\pipedel{\delimiter\the\delcode`|}
\mathchardef\lt\mathcode`<
\mathchardef\pipechar\mathcode`|
\mathchardef\gt\mathcode`>
\mathcode`\<=\string"8000
\mathcode`\|=\string"8000
\mathcode`\>=\string"8000
\left.
#2
\right.
\endgroup
}}
Все следующие варианты использования работают так, как и ожидалось:
\braket{<\psi|\psi>}
\braket{<\psi|A|\psi>}
\braket{<\psi|\frac{p^2}{2m}|\psi>}
\braket[\Big]{<\alpha|\beta>}
\braket{|a \gt 0>}
\braket[]{<\psi|\frac{p^2}{2m}|\phi>}
(последний вариант просто отключает автоматическую адаптацию размера).
Однако, следующее делаетнетработают правильно:
\braket{<0|1>}
Он должен выдать «〈0|1〉», но выдает только «〈0〉».
Так что же не так с моим макросом и как это исправить?
решение1
Проблема в том, что когда TeX находит активный канал, он расширяет его до
\delimiter 2532108
и следующий за ним номер будет включен в этот код.
\mathchardef\lt\mathcode`<
\mathchardef\pipechar\mathcode`|
\mathchardef\gt\mathcode`>
\edef\pipedel{\delimiter\the\delcode`| }
\show\pipedel
\newcommand{\braket}[2][\middle]{
\begingroup
\begingroup\lccode`~=`<
\lowercase{\endgroup\def~}{#1\langle}
\begingroup\lccode`~=`|
\lowercase{\endgroup\def~}{#1\pipedel\relax}
\begingroup\lccode`~=`>
\lowercase{\endgroup\def~}{#1\rangle}
\mathcode`\<=\string"8000
\mathcode`\|=\string"8000
\mathcode`\>=\string"8000
\mathopen{}\left.#2\right.\mathclose{}
\endgroup
}
Это \relax
позволит избежать проблемы. Также некоторые части лучше за пределами определения и \ensuremath
не рекомендуются.
Примечание к \lowercase
трюку
Когда символу (с кодом категории 11 или 12) назначен математический код "8000
и он находится в математическом режиме, TeX обрабатывает его так, как если бы он был активным (то есть как макрос), и требуется его определение как активного символа.
Очень часто используемый трюк — это использовать это~
являетсяактивный; когда мы хотим придать значение активному <
, есть две стратегии. Первая -
{\catcode`<=\active \gdef<{something}}
что имеет некоторые недостатки: мы вынуждены выполнять его заранее, и этоГлобальный. Поэтому мы используем другую стратегию:
\begingroup\lccode`~=`< \lowercase{\endgroup\def~}{something}
Как это работает? Сначала мы открываем группу и в группе говорим TeX, что строчный аналог — ~
это <
. Затем мы делаем \lowercase
, что преобразуетжетоны персонажейв их строчные аналоги (но оставляя управляющие последовательности неизменными) и возвращает токены, как будто они были там с самого начала. Так TeX видит
\endgroup\def<{something}
(но<
являетсяактивный, так как \lowercase
не изменяет коды категорий). \endgroup
Отменяет соответствие между ~
и <
и выполняется определение. Когда позже мы скажем \mathcode`<=\string"8000
, произойдет волшебство ( \string
предосторожность противвавилонкоторый мог бы стать "
активным персонажем).