Определение макроса с несколькими аргументами и использование \csname

Определение макроса с несколькими аргументами и использование \csname

Почему следующий код не работает?

\Requirepackage{amsthm}
\renewcommand\newtheorem[2]{%
    \NewEnviron{\csname #1\endcsname}[1]{%
        ##1 : \BODY
    }
}

Я видел примеры использования \csname SOMENAME\endcsnameмакроса for без аргументов, но не знаю, как это сделать с \NewEnvironили \newcommandс несколькими аргументами. Мне выдается сообщение об ошибке ! Missing \endcsname inserted.

решение1

Вам не нужно имя команды для имени среды. Достаточно просто имени.

Итак, вы можете сделать это:

\documentclass{article}
\usepackage{amsthm,environ}
\renewcommand\newtheorem[2]{%
    \NewEnviron{#1}[1]{%
        ##1 : \BODY
    }%
}
\begin{document}
\newtheorem{acorns}{oaks}
\begin{acorns}{trees}
  leaves and things
\end{acorns}
\end{document}

Обратите внимание, что этот код не требуетамстм, вы можете просто использовать его, \newcommand\newtheorem...если только пакет вам не нужен по другим причинам.

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

Я не уверен, что это действительно то, что вы хотите сделать. Вывод из кода выше:

деревья и листья и вещи

КакКристиан Хапфер отмечает, это, конечно, сломает все, что использует \newtheoremв стандартном смысле. Какэгрег говорит, совсем не очевидно, какой цели \newtheoremслужит такое переопределение. Кажется, это почти гарантированно приведет к проблемам рано или поздно... скорее всего рано.

решение2

Почему следующий код не работает?

Давайте подробнее рассмотрим, что \NewEnvironделает:

После короткой цепочки макросов для правильного анализа пользовательского ввода \NewEnvironиспользуется \env@newenvironmentто, что было \letв \newenvironmentначале.

Теперь, \newenvironmentвнутренне делает среди прочего (немного упрощенно) что-то вроде

\expandafter\def\csname <env-name>\endcsname{<begin-code>}

(По сути, вы поступили правильно, не зная, что внутренние механизмы уже об этом позаботились.)

Если вы установите " <env-name>=\csname SOMENAME\endcsname" (что может произойти в результате использования вашего пользовательского макроса \newtheorem{SOMENAME}{}), то в результате вы получите лишнюю \csname...\endcsnameпару:

\expandafter\def\csname\csname SOMENAME\endcsname\endcsname...

\expandafter(как вы, вероятно, знаете) в этом случае захватывает \defи сохраняет его, чтобы смотреть вперед на следующий токен и расширяет его первым. Здесь он находит, \csnameкоторый ищет следующий \endcsnameи расширяет все, что между ними, и формирует из этого управляющую последовательность. Это будет еще один \csname, который снова правильно завершается завершающим \endcsname. Таким образом, вы действительно применяете механизм \csnameдважды к 'SOMENAME', и это означает, что вы не получаете \def\SOMENAME{<begin-code>}(как вы планировали), а получаете

\def\<expansion of \SOMENAME>{<begin-code>}

Если \SOMENAMEбыло определено, у нас не было проблем:

\documentclass{article}
\usepackage{environ}

\def\SOMENAME{somename}
\NewEnviron{\csname SOMENAME\endcsname}{somename-content: \BODY}

\begin{document}
\begin{somename}
  Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  Integer feugiat tempus urna, cursus placerat sapien mollis ac.
  Donec a accumsan orci, in tristique ligula.
\end{somename}
\end{document}

Но вам следуетнетопределить его; этот пользовательский интерфейс будет каким-то образом вводить в заблуждение. Просто используйте \NewEnvironточно так же, как \newenvironmentв отношении ввода имени окружения:

\documentclass{article}
\usepackage{environ}

\newcommand{\FlorianEnvdefWrapper}[1]{%
  \NewEnviron{#1}[1]{##1: \BODY}
}

\FlorianEnvdefWrapper{somename}

\begin{document}
\begin{somename}{foo-bar}
  Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  Integer feugiat tempus urna, cursus placerat sapien mollis ac.
  Donec a accumsan orci, in tristique ligula.
\end{somename}
\end{document}

Замечание

Я изменил имя вашего примера макроса, чтобы избежать конфликтов с пакетом amsthm. Я думаю, что лучше оставить эти вещи такими, какие они есть, в общем. Конечно, есть исключения, но полная потеря его функциональности может быть не лучшим вариантом, если вы можете этого избежать, просто выбрав другое имя для своей команды.

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