¿Cuál es la forma preferida de expandir dos veces en expl3?

¿Cuál es la forma preferida de expandir dos veces en expl3?

expl3incluye los especificadores de argumentos o, fy xpara 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 l3keysinterfaz clave-valor para macros creadas \DeclarePairedDelimiterdesde el mathtoolspaquete.

\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 \bigetc. o *, como por ejemplo \abs[\big]{x}dónde \DeclarePairedDelimiter\abs{\lvert}{\rvert}. Preferiría tener size = bigetc. o size = autocomo una interfaz clave-valor, como \myabs[size=big]{x}.

El problema con el código anterior viene al configurar correctamente \l__mymodule_size_tlen las bigopciones, 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 \absobtiene su argumento en la forma incorrecta: \l__mymodule_size_tlse 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_tlse mantendrá [ \cs:w \tl_use:N \l_keys_choice_tl \cs_end: ], no [\big].
  • Si uso cualquiera de los dos fo xla expansión, \l__mymodule_size_tlcontendrá un montón de "basura", no [\big].

¿Qué puedo hacer? Aquí tienes una idea: utiliza dos oexpansiones, 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 dtipo 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 toksregistros en general. De memoria, expl3hay dos lugares donde tuvimos que ir con un constructo de la \exp_args:NNo \exp_args:Noforma o similar.

La razón por la que no conservamos dlos 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 xcontextos 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 xla expansión \exp_not:cse dispara, por lo que el argumento se expande completamente como siempre cuando cestá 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.

información relacionada