
Estaba revisando esta respuesta y tratando de entender el código, soy un súper novato (mi segundo día) en LaTeX y me quedé atascado en la siguiente parte del código que no podía hacer que funcionara en un entorno sin tabla. Aquí está la forma más simple de lo que no entiendo.
\documentclass{article}
\begin{document}
\newcommand*\f[3]{#1-#2-#3}
\newcommand*\ex[1]{\f#1 - \expandafter\f\@firstofone}
Try \ex{111}{221}
\end{document}
Por alguna razón, que no me queda clara, en el código vinculado, el último argumento no se consume, pero la construcción lo deja consumir expandafter\f\...
. Por lo que tengo entendido, \expandafter
primero debería "ejecutarse" \@firstofone
, obtener el {221}
argumento, quitar los corchetes y enviarlo a \f
. Esto no sucede y no puedo entender por qué.
Respuesta1
Necesitas usar \makeatletter
para que esto funcione, pero es lo de menos.
La convocatoria \ex{111}{221}
se expande primero a
\f 111 - \expandafter\f\@firstofone{221}
Ahora \f
está expandido y busca tres argumentos, encontrando 1
y 1
, 1
porque TeX usa un solo token si falta una llave.
Por la definición de \f
esto se expande y el texto de reemplazo se reinserta en el flujo de entrada:
1-1-1 - \expandafter\f\@firstofone{221}
Los tokens 1-1-1 -
no son ampliables y por eso se envían a la siguiente etapa. ahora queda
\expandafter\f\@firstofone{221}
Esto dejará \f
de lado y expandirá \@firstofone
lo que simplemente devuelve su (argumento sin refuerzos), por lo que obtenemos
\f221
eso se convierte en 2-2-1
. Por lo tanto, el efecto neto de su código es imprimir
1-1-1 - 2-2-1
lo cual no parece realmente útil. Dondequiera que lo hayas encontrado, no confíes en él.
Respuesta2
Como señaló egreg en su respuesta, el uso de \@firstofone
no es muy útil y no hace una diferencia en este caso particular. Sin embargo, hay casos en los queesútil. Para completar, me gustaría dar dos ejemplos.
Macros ampliables
En¿Por qué el \expandafter\@firstoftwo
modismo?Se proporciona un caso de uso típico para \@firstoftwo
y en macros totalmente expandibles. , una especie de "función de identidad" de LaTeX, es útil en contextos similares donde solo se debe manejar un único parámetro:\@secondoftwo
\@firstofone
\def\gobbleIfZero#1{%
\ifnum#1=0
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
}
foo\gobbleIfZero{0}{bar}
foo\gobbleIfZero{123}{bar}
daré
foo
Foobar
\@gobble
(como \@firstofone
) toma un solo parámetro pero lo descarta y se expande a "nada".
Fijación de códigos cat
Un poco más complicado pero también más interesante es el caso en el que están involucrados cambios de código cat. Cuando TeX analiza argumentos para macros, corrige códigos cat cada vez que se lee el texto del argumento. Esto no importa en su caso ya que aquí no hay cambios en los códigos cat. Pero supongamos que se da el siguiente ejemplo algo artificial:
\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}}
Esto resulta en
3cuatro5-3cuatro5
345-3cuatro5
Las primeras cuatro líneas definen una macro global 4
que se expande a four
. Generalmente 4
tiene catcode 12 (otro), por lo que lo cambiamos a 13 (activo) para poder crear una macro con él. \f
aquí devuelve estas macros al alcance cuando se ejecuta.
Cuando \exA
se ejecuta, el código cat 4
se cambia a 13, lo que luego hace que 4
se expanda four
en los dos grupos siguientes. Aquí no hay ningún parámetro, por lo que esto es sencillo.
Por otro lado, en la macro se procesa \exB
la primera parte , la cual simplemente devuelve el mismo texto,{345}
\@firstofone
pero arregla el catcodede 4
a 12. Una vez que se soluciona, ¡ya no se puede cambiar! Aunque \f
se procesa el cambio de catcodeantesel primero 345
, no tendrá ningún efecto sobre él. Como los catcodes del segundo {345}
aún no se han solucionado, los cambios seguirán aplicándose a este grupo.
Este comportamiento resulta muy útil si desea inyectar código adicional en macros existentes que se ocupan de cambios de código cat, por ejemplo \verb
(inspirado enesta perla de 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
que salidas
No sé dónde leíste \@firstofone
en primer lugar, pero podría haber sido en uno de estos contextos.