Какой предпочтительный способ двойного расширения в expl3?

Какой предпочтительный способ двойного расширения в expl3?

expl3включает спецификаторы аргумента o, f, и xдля одноуровневого и двух видов полного расширения соответственно, перед передачей аргумента базовой функции. Какой предпочтительный способ расширения аргументадваждыперед передачей его базовой функции?

В качестве примера я пытаюсь написать l3keysинтерфейс «ключ-значение» для макросов, созданных с помощью \DeclarePairedDelimiterпакета mathtools.

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

Обычно размер разделителей передается макросу как необязательный аргумент \bigetc. или *, например, \abs[\big]{x}where \DeclarePairedDelimiter\abs{\lvert}{\rvert}. Я бы предпочел иметь size = bigetc. или size = autoкак интерфейс ключ-значение, например, \myabs[size=big]{x}.

Проблема с приведенным выше кодом заключается в правильной настройке \l__mymodule_size_tlв bigпараметрах etc.: мне нужно расширить[ \use:c { \tl_use:N \l_keys_choice_tl } ] дваждыперед назначением этих токенов \l__mymodule_size_tl.

  • Если я не использую расширение (т. е. \tl_set:Nn), вызов \absполучит свой аргумент в неправильной форме — \l__mymodule_size_tlбудет содержать [ \use:c { \tl_use:N \l_keys_choice_tl } ], а не [\big].
  • Если я использую одноуровневое расширение (т. е. \tl_set:No) и добавлю его [после завершения расширения, \l__mymodule_size_tlто будет храниться [ \cs:w \tl_use:N \l_keys_choice_tl \cs_end: ], а не [\big].
  • Если я использую расширение fили x, \l__mymodule_size_tlбудет храниться куча «мусора», а не [\big].

Что я могу сделать? Вот идея: использовать два oрасширения, с некоторой акробатикой между ними.

    \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 { [ }

По-моему, это довольно некрасиво. Можно ли сделать что-то получше?

решение1

В былые времена существовал dаргумент типа - для двойного расширения. Однако несколько лет назад он был отброшен, поскольку было очень мало мест, где он требовался, особенно когда команда решила toksвообще не использовать регистры. По памяти, в expl3двух местах нам пришлось использовать конструкцию \exp_args:NNo \exp_args:Noили подобную форму.

Причина, по которой мы не сохранили dаргументы -type, двояка. Во-первых, мы хотим избежать, где это возможно, опоры на знание деталей расширения функций: это требуется для низкоуровневой работы, но в идеале должно быть относительно ограничено. Другая причина в том, что это требуется очень редко, поскольку у нас есть e-TeX. Главное помнить, что это позволяет нам контролировать расширение в xконтекстах -type

\tl_set:Nx \l__mymodule_size_tl
  { [ \exp_not:c { \tl_use:N \l_keys_choice_tl } ] }

Хотя здесь это не требуется, мы документируем \cs:w... \cs_end:для ситуаций, когда требуется только одно расширение, поэтому вы можете иметь

\tl_set:No \l__mymodule_size_tl
  { \exp_after:wN [ \cs:w \tl_use:N \l_keys_choice_tl \cs_end: ] }

хотя я бы не стал использовать это здесь.

решение2

У меня сложилось впечатление, что вы хотите сделать

\tl_set:Nx \l__mymodule_size_tl
 {
  [ \exp_not:c { \tl_use:N \l_keys_choice_tl } ]
 }

При срабатывании xрасширения \exp_not:cаргумент полностью расширяется, как всегда, когда cзадействован (это \csname...\endcsname); затем результирующий токен становится нерасширяемым, поэтому если у вас есть

size=big

вы попадете [\big]в свой список токенов.

Связанный контент