expl3
incluye los especificadores de argumentos o
, f
y x
para un nivel y los dos tipos de expansión completa, respectivamente, antes de pasar el argumento a la función base. ¿Cuál es la forma preferida de ampliar un argumento?dos vecesantes de pasarlo a la función base?
Como ejemplo, estoy intentando escribir una l3keys
interfaz clave-valor para macros creadas \DeclarePairedDelimiter
desde el mathtools
paquete.
\tl_new:N \l__mymodule_size_tl
\keys_define:nn { mymodule }
{
size .choices:nn =
{ big , Big , bigg , Bigg }
{
\tl_set:Nn \l__mymodule_size_tl
{ [ \use:c { \tl_use:N \l_keys_choice_tl } ] }
} ,
size / auto .code:n =
\tl_set:Nn \l__mymodule_size_tl {*} ,
size / none .code:n =
\tl_clear:N \l__mymodule_size_tl
}
Por lo general, el tamaño de los delimitadores se pasa a la macro como un argumento opcional de \big
etc. o *
, como por ejemplo \abs[\big]{x}
dónde \DeclarePairedDelimiter\abs{\lvert}{\rvert}
. Preferiría tener size = big
etc. o size = auto
como una interfaz clave-valor, como \myabs[size=big]{x}
.
El problema con el código anterior viene al configurar correctamente \l__mymodule_size_tl
en las big
opciones, etc.: necesito expandir[ \use:c { \tl_use:N \l_keys_choice_tl } ]
dos vecesantes de asignar esos tokens a \l__mymodule_size_tl
.
- Si no uso ninguna expansión (es decir,
\tl_set:Nn
), la llamada a\abs
obtiene su argumento en la forma incorrecta:\l__mymodule_size_tl
se mantendrá[ \use:c { \tl_use:N \l_keys_choice_tl } ]
, no[\big]
. - Si uso una expansión de un nivel (es decir,
\tl_set:No
) y antepongo[
una vez completada la expansión,\l__mymodule_size_tl
se mantendrá[ \cs:w \tl_use:N \l_keys_choice_tl \cs_end: ]
, no[\big]
. - Si uso cualquiera de los dos
f
ox
la expansión,\l__mymodule_size_tl
contendrá un montón de "basura", no[\big]
.
¿Qué puedo hacer? Aquí tienes una idea: utiliza dos o
expansiones, con algunas acrobacias entre ellas.
\tl_set:No \l__mymodule_size_tl
{ \use:c { \tl_use:N \l_keys_choice_tl } ] }
\exp_args:NNV \tl_set:No \l__mymodule_size_tl
\l__mymodule_size_tl
\tl_put_left:Nn \l__mymodule_size_tl { [ }
En mi opinión, esto es bastante feo. ¿Hay algo mejor que pueda hacer?
Respuesta1
En tiempos de antaño había un d
tipo de argumento a favor de la doble expansión. Sin embargo, se abandonó hace algunos años porque había muy pocos lugares donde era necesario, particularmente cuando el equipo decidió no utilizar toks
registros en general. De memoria, expl3
hay dos lugares donde tuvimos que ir con un constructo de la \exp_args:NNo \exp_args:No
forma o similar.
La razón por la que no conservamos d
los argumentos de tipo es doble. En primer lugar, queremos evitar, en la medida de lo posible, depender del conocimiento de los detalles de expansión de las funciones: esto es necesario para trabajos de bajo nivel, pero idealmente debería ser relativamente limitado. La otra razón es que rara vez se necesita ya que tenemos e-TeX disponible. La clave para recordar es que esto nos permite controlar la expansión en x
contextos de tipo
\tl_set:Nx \l__mymodule_size_tl
{ [ \exp_not:c { \tl_use:N \l_keys_choice_tl } ] }
Si bien no es necesario aquí, documentamos \cs:w
... \cs_end:
para situaciones en las que se requiere exactamente una expansión, por lo que podría tener
\tl_set:No \l__mymodule_size_tl
{ \exp_after:wN [ \cs:w \tl_use:N \l_keys_choice_tl \cs_end: ] }
aunque yo no lo usaría aquí.
Respuesta2
Mi impresión es que quieres hacer
\tl_set:Nx \l__mymodule_size_tl
{
[ \exp_not:c { \tl_use:N \l_keys_choice_tl } ]
}
Con x
la expansión \exp_not:c
se dispara, por lo que el argumento se expande completamente como siempre cuando c
está involucrado (es \csname...\endcsname
); entonces el token resultante no se puede expandir, por lo que si tiene
size=big
entrarás [\big]
en tu lista de tokens.