¿Cómo implementar \expandbefore, de manera similar a \expandafter?

¿Cómo implementar \expandbefore, de manera similar a \expandafter?

Estoy intentando definir un nuevo comando, pero especificando la nueva cadena de control "sobre la marcha" usando csnamey endcsname.(Esto tiene como objetivo implementar un patrón de inyección de dependencia). **Alternativamente, ¿hay alguna manera de hacer esto con expl3?

Normalmente, he estado usando \expandafter\newcommand... pero en este caso de uso, me gustaría definir el primer parámetro de csnameWithin \newcommand, así:

\newcommand{\expandbefore\csname \GetCommandName \endcsname}[1]{\small I did it!!!}
\newcommand\expandbefore\csname \GetCommandName \endcsname{\small I did it again!!!}

Me gustaría que todo lo que está dentro de las llaves se expanda ANTES de \newcommand...pero sin depender de \expandafterantes\newcommand.

Asuntos:

  • Tengo curiosidad por saber si existe una forma normal de hacer esto en LaTeX, sin tener que depender de otro truco del búfer de entrada del proceso (con Lua).

  • Agregar expandafter, nameuse, edef, let, csname, etc, dentro del \newcommandparámetro 's solo da como resultado un error al redefinir esos comandos. (Incluso si está en {}o begingroupcierres.

  • Intentar \meaning \expandafterdescubrir cómo funciona falla (de manera predecible y también divertida).

Respuesta1

Yo (con ligeras modificaciones) cito mirespuestaa la preguntaDefinir una secuencia de control después de que un espacio importeya que parece aplicarse también a su pregunta:


Al aplicar la #{notación -, puede definir macros cuyo último argumento esté delimitado por una llave de apertura. A diferencia de otros delimitadores de argumentos que se eliminan al recopilar argumentos, TeX dejará una llave de apertura delimitadora en su lugar.
(En realidad, el mecanismo no se limita a abrir tokens de caracteres de llave. Puede usar cualquier token cuyo código de categoría sea 1 en el momento de la definición. También podría ser #\WeIrdposterior \let\WeIrd={  ).
Los argumentos delimitados pueden estar vacíos.

Por lo tanto, para obtener un token de secuencia de control a partir de un conjunto de tokens que se expande a un conjunto de tokens de caracteres que forma el nombre del token de secuencia de control en cuestión, tanto para definir como para llamar a ese token de secuencia de control, puede (aplicando la #{notación - ) inventa una secuencia de control única \nameque procesa un argumento delimitado por llaves seguido por un argumento no delimitado (que está anidado entre llaves). Después de que TeX obtenga los argumentos, puede hacer que TeX los haga girar y los aplique \csname..\endcsnameal argumento proporcionado entre llaves. El nombre del token de secuencia de control en cuestión también puede contener tokens de espacio.

\makeatletter
%
\newcommand\name{}%
\long\def\name#1#{\UD@innername{#1}}%
%
\newcommand\UD@innername[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{#1}%
}%
%
\newcommand\UD@exchange[2]{#2#1}%
%
\makeatother

\name foo{bar}→ paso de expansión 1:
\UD@innername{foo}{bar}→ paso de expansión 2:
\expandafter\UD@exchange\expandafter{\csname bar\endcsname}{foo}→ paso de expansión 3:
\UD@exchange{\bar}{foo}→ paso de expansión 4:
foo\bar  .

En contextos de expansión, necesitaría cuatro \expandaftercadenas para obtener el resultado.

Como \romannumeralno se produce ningún token cuando se encuentra un número no positivo, puede agregar un poco de \romannumeralexpansión para reducir la cantidad de \expandaftercadenas.

O hazlo \romannumeral\name0 foo{bar}. De esta manera, solo se necesita una \expandaftercadena que golpee el \romannumeraltoken.

O tenga la \romannumeralexpansión "codificada" dentro de la definición; de esta manera \expandafterse necesitan dos cadenas. El primero para obtener la expansión de nivel superior de \name. El segundo para inducir \romannumeralla expansión.

\makeatletter
%
\newcommand\name{}%
\long\def\name#1#{\romannumeral0\UD@innername{#1}}%
%
\newcommand\UD@innername[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{ #1}%
}%
%
\newcommand\UD@exchange[2]{#2#1}%
%
\makeatother

Con una macro de este tipo no estás obligado a comandos de definición específicos:

\name{foo}\foo  .    (←Esta es la forma en la que no defines sino que simplemente llamas/usas secuencias de control mediante \name.)

\name\newcommand{foo}\newcommand\foo  .

\name\DeclareRobustCommand{foo}\DeclareRobustCommand\foo  .

\name\global\long\outer\def{foo}\global\long\outer\def\foo  .

\name\expandafter{foo}\bar\expandafter\foo\bar  .

\name\let{foo}=\bar\let\foo=\bar  .

\name\string{foo}\string\foo  .

\name\meaning{foo}\meaning\foo  .

También puede utilizar una macro de este tipo para definir/llamar macros cuyos nombres contengan espacios:

\name{foo }\foo␣  .

\name\newcommand{foo }\newcommand\foo␣  .

\name\DeclareRobustCommand{foo }\DeclareRobustCommand\foo␣  .

\name\global\long\outer\def{foo }\global\long\outer\def\foo␣  .

\name\expandafter{foo }\bar\expandafter\foo␣\bar  .

\name\let{foo }=\bar\let\foo␣=\bar  .

\name\string{foo }\string\foo␣  .

\name\meaning{foo }\meaning\foo␣  .

Al recopilar el nombre del token de secuencia de control en cuestión, \namese activará la expansión de tokens expandibles:

\def\GetCommandName{FooBar}
\name\newcommand{\GetCommandName}[1]{\small I did it!!!}

\newcommand\FooBar[1]{\small I did it!!!}

\def\GetCommandName{\CommandNamePartA\CommandNamePartB}
\def\CommandNamePartA{Ba}
\def\CommandNamePartB{r\InnerCommandNamePart o}
\def\InnerCommandNamePart{Fo}
\name\newcommand{\GetCommandName}{\small I did it again!!!}

\newcommand\BarFoo{\small I did it again!!!}

También puedes anidar las llamadas a \name:

Ejemplo 1:

   \name\name\expandafter{f o o }{b a r }

Procesando los primeros \namerendimientos:
   \name\expandafter\f␣o␣o␣{b a r }  .

Al procesar el segundo \namese obtiene:
   \expandafter\f␣o␣o␣\b␣a␣r␣  .

(De manera análoga: \name\name\let{f o o }={b a r }\let\f␣o␣o␣=\b␣a␣r␣.)

Ejemplo 2:

   \name\name\name\expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

Procesando los primeros \namerendimientos:
   \name\name\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  .

Al procesar el segundo \namese obtiene:
   \name\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  .

Procesando el tercero \namese obtiene:
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Ejemplo 3:

En contextos de expansión, puede utilizar \romannumeral-expansion para que todo siga funcionando.

   \romannumeral\name\name\name0 \expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

\romannumeralcontinúa expandiéndose hasta que encuentra algún número. Al final encontrará el número 0mientras que con números no positivos \romannumeralno entregará ningún token:
   %\romannumneral-expansion in progress
   \name\name\name0 \expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

Procesando los primeros \namerendimientos:
   %\romannumneral-expansion in progress
   \name\name0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  .

Al procesar el segundo \namese obtiene:
   %\romannumneral-expansion in progress
   \name0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  .

Procesando el tercero \namese obtiene:
   %\romannumneral-expansion in progress
   0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Ahora \romannumeralencuentra el número 0. Por lo tanto, \romannumeralla expansión se cancela y \romannumeralno entregará ningún token:
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Tenga en cuenta que \namese aplica internamente \csnamemientras

  • La expansión de los tokens expandibles se lleva a cabo mientras, \csnamedurante su búsqueda de la coincidencia, \endcsnamereúne los tokens de personajes que forman el nombre del token de secuencia de control en cuestión.

  • aplicar \csnamecomo efecto secundario produce asignar a la secuencia de control en cuestión el significado de la \relaxprimitiva en caso de que la secuencia de control en cuestión no estuviera definida antes de la aplicación \csname. Esa asignación se restringirá al alcance actual incluso si el \globaldefsparámetro tenía un valor positivo en el momento de la solicitud \csname.

 

%%\errorcontextlines=1000
\documentclass[a4paper]{article}
\usepackage{textcomp}%

\parindent=0cm
\parskip=\medskipamount

\makeatletter
\newcommand\name{}%
\long\def\name#1#{\romannumeral0\UD@innername{#1}}%
\newcommand\UD@innername[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{ #1}%
}%
\newcommand\UD@exchange[2]{#2#1}%
\makeatother


\name\newcommand{foo}[2]{%
  Control sequence whose name does not contain any space.\\
  Argument 1: \textit{\textlangle#1\textrangle}\\
  Argument 2: \textit{\textlangle#2\textrangle}
}%

\name\newcommand{foo }[2]{%
  Control sequence whose name has a trailing space.\\
  Argument 1: \textit{\textlangle#1\textrangle}\\
  Argument 2: \textit{\textlangle#2\textrangle}
}%

\name\newcommand{ f o o }[2]{%
  Control sequence whose name is interspersed with spaces.\\
  Argument 1: \textit{\textlangle#1\textrangle}\\
  Argument 2: \textit{\textlangle#2\textrangle}
}%

\newcommand*\GetCommandName{\CommandNamePartA\CommandNamePartB}
\newcommand*\CommandNamePartA{Ba}
\newcommand*\CommandNamePartB{r\InnerCommandNamePart o}
\newcommand*\InnerCommandNamePart{Fo}
\name\newcommand{\GetCommandName}{\small I did it again!!!}

\begin{document}

\name{foo}{Arg 1}{Arg 2}

\name{foo }{Arg 1}{Arg 2}

\name{ f o o }{Arg 1}{Arg 2}

Nesting \texttt{\string\name}:

\name\expandafter\newcommand\expandafter*\expandafter{C o N f u SiO n}\expandafter{%
  \romannumeral\name\name\name0 %
  \expandafter\expandafter\expandafter{F O O}\expandafter{B A R}{C R A Z Y}%
}%
\texttt{\name\string{C o N f u SiO n} is \name\meaning{C o N f u SiO n}}%
\\

Playing around with expandable tokens:  

\texttt{\name\string{\GetCommandName}:}
\texttt{\name\meaning{\GetCommandName}}

\name{\GetCommandName}%

Playing around with grouping:

%Be aware that \texttt itself opens up a new scope for typesetting its argument.

%\globaldefs=1\relax

\texttt{%
  \begingroup\name\string{w e i r d } is  \name\endgroup\meaning{w e i r d }%
}%

\texttt{%
  \name\string{w e i r d } is  \name\meaning{w e i r d }%
}%

\end{document}

ingrese la descripción de la imagen aquí

Respuesta2

LaTeX ya tiene un formulario de comando que toma el nombre de un comando en lugar del token csname:

\@namedef{\GetCommandName}{\small I did it!!!}

deberías hacer lo que quieras esto es simplemente\expandafter\def\csname\GetCommandName\endcsname{..}

información relacionada