Como implementar \expandbefore, de forma semelhante a \expandafter?

Como implementar \expandbefore, de forma semelhante a \expandafter?

Estou tentando definir um novo comando, mas especificando a nova string de controle "on the fly" usando csnamee endcsname.(Isso tem como objetivo implementar um padrão de injeção de dependência.) **Alternativamente, existe uma maneira de fazer isso com expl3?

Normalmente, tenho usado \expandafter\newcommand... mas neste caso de uso, gostaria de definir o primeiro parâmetro do csnameWITHIN \newcommand, assim:

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

Eu gostaria que tudo dentro do aparelho fosse expandido ANTES \newcommand-mas sem depender de \expandafterantes\newcommand.

Problemas:

  • Estou curioso para saber se existe uma maneira normal de fazer isso no LaTeX, sem ter que depender de outro hack do buffer de entrada do processo (com Lua).

  • Adicionar expandafter, nameuse, edef, let, csname, etc, dentro do \newcommandparâmetro apenas resulta em um erro ao redefinir esses comandos. (Mesmo que esteja dentro {}ou begingroupfechado.

  • Tentar \meaning \expandafterdescobrir como funciona falha (previsivelmente e engraçado também).

Responder1

Eu (com pequenas modificações) cito meuresponderpara a perguntaDefina uma sequência de controle depois que um espaço for importantecomo parece se aplicar à sua pergunta também:


Ao aplicar a #{notação -, você pode definir macros cujo último argumento é delimitado por uma chave de abertura. Ao contrário de outros delimitadores de argumentos que são removidos ao coletar argumentos, o TeX deixará uma chave de abertura delimitadora no lugar.
(Na verdade, o mecanismo não está restrito à abertura de tokens de caracteres entre chaves. Você pode usar qualquer token cujo código de categoria seja 1 no momento da definição. Poderia muito bem ser #\WeIrddepois de \let\WeIrd={  .)
Os argumentos delimitados podem estar vazios.

Portanto, para obter um token de sequência de controle de um conjunto de tokens que se expande para um conjunto de tokens de caracteres que forma o nome do token de sequência de controle em questão, tanto para definir quanto para chamar esse token de sequência de controle, você pode (aplicando a #{notação - ) inventam uma única sequência de controle \nameque processa um argumento delimitado por colchetes seguido por um argumento não delimitado (que está aninhado entre colchetes). Depois de fazer com que o TeX busque os argumentos, você pode fazer com que o TeX os gire e aplique \csname..\endcsnameao argumento fornecido entre colchetes. O nome do token de sequência de controle em questão também pode conter tokens de espaço.

\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}→ etapa de expansão 1:
\UD@innername{foo}{bar}→ etapa de expansão 2:
\expandafter\UD@exchange\expandafter{\csname bar\endcsname}{foo}→ etapa de expansão 3:
\UD@exchange{\bar}{foo}→ etapa de expansão 4:
foo\bar  .

Em contextos de expansão, você precisaria de quatro \expandaftercadeias para obter o resultado.

Como \romannumeralnão produz nenhum token ao encontrar um número não positivo, você pode adicionar um pouco de \romannumeral-expansão para reduzir a quantidade de \expandafter-chains.

Ou faça \romannumeral\name0 foo{bar}. Dessa forma, apenas uma \expandafter-chain atingindo o \romannumeral-token é necessária.

Ou tenha a \romannumeral-expansão "codificada" dentro da definição - dessa forma, duas \expandaftercadeias são necessárias. O primeiro para obter a expansão de nível superior de \name. O segundo para induzir \romannumerala expansão.

\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

Com essa macro você não está vinculado a comandos de definição específicos:

\name{foo}\foo  .    (←Esta é a maneira pela qual você não define, mas apenas chama/usa sequências de controle por meio de \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  .

Você também pode usar essa macro para definir/chamar macros cujos nomes contenham espaços:

\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␣  .

Ao coletar o nome do token de sequência de controle em questão, \nameacionará a expansão de tokens expansíveis:

\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!!!}

Você também pode aninhar as chamadas para \name:

Exemplo 1:

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

Processando os primeiros \namerendimentos:
   \name\expandafter\f␣o␣o␣{b a r }  .

Processando os segundos \namerendimentos:
   \expandafter\f␣o␣o␣\b␣a␣r␣  .

(Análogos: \name\name\let{f o o }={b a r }\let\f␣o␣o␣=\b␣a␣r␣.)

Exemplo 2:

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

Processando os primeiros \namerendimentos:
   \name\name\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  .

Processando os segundos \namerendimentos:
   \name\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  .

Processando o terceiro \namerendimento:
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Exemplo 3:

Em contextos de expansão você pode usar \romannumeral-expansion para manter as coisas funcionando.

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

\romannumeralcontinua se expandindo até encontrar algum número. No final ele encontrará o número 0enquanto com números não positivos \romannumeralnão entregará nenhum token:
   %\romannumneral-expansion in progress
   \name\name\name0 \expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

Processando os primeiros \namerendimentos:
   %\romannumneral-expansion in progress
   \name\name0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  .

Processando os segundos \namerendimentos:
   %\romannumneral-expansion in progress
   \name0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  .

Processando o terceiro \namerendimento:
   %\romannumneral-expansion in progress
   0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Agora \romannumeralencontra o número 0. Portanto \romannumeral-expansion é abortado e \romannumeralnão entrega nenhum token:
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Esteja ciente de que \namese aplica internamente \csnameenquanto

  • a expansão dos tokens expansíveis ocorre enquanto \csnamedurante sua busca pela correspondência \endcsnamereúne os tokens de caracteres que formam o nome do token da sequência de controle em questão.

  • aplicar \csnamecomo efeito colateral resulta em atribuir à sequência de controle em questão o significado do \relax-primitivo caso a sequência de controle em questão tenha sido indefinida antes da aplicação \csname. Essa atribuição será restrita ao escopo atual, mesmo que o \globaldefsparâmetro -tenha um valor positivo no momento da aplicação \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}

insira a descrição da imagem aqui

Responder2

O LaTeX já possui um formulário de comando que recebe o nome de um comando em vez do token csname:

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

deve fazer o que quiser, isso é simplesmente\expandafter\def\csname\GetCommandName\endcsname{..}

informação relacionada