expl3
enthält die Argumentspezifizierer o
, f
, und x
für eine einstufige bzw. die beiden Arten der vollständigen Erweiterung, bevor das Argument an die Basisfunktion übergeben wird. Was ist die bevorzugte Art der Erweiterung eines Arguments?zweimalbevor Sie es an die Basisfunktion übergeben?
Als Beispiel versuche ich, eine l3keys
Schlüssel-Wert-Schnittstelle für Makros zu schreiben, die mit \DeclarePairedDelimiter
dem mathtools
Paket erstellt wurden.
\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
}
Normalerweise wird die Größe der Trennzeichen als optionales Argument von \big
usw. oder an das Makro übergeben *
, z. B. \abs[\big]{x}
wobei . Ich hätte usw. oder \DeclarePairedDelimiter\abs{\lvert}{\rvert}
lieber als Schlüssel-Wert-Schnittstelle, wie z. B. .size = big
size = auto
\myabs[size=big]{x}
Das Problem mit dem obigen Code besteht darin, \l__mymodule_size_tl
die big
Auswahlmöglichkeiten usw. richtig einzustellen: Ich muss erweitern[ \use:c { \tl_use:N \l_keys_choice_tl } ]
zweimalbevor diese Token zugewiesen werden \l__mymodule_size_tl
.
- Wenn ich keine Erweiterung verwende (d. h.
\tl_set:Nn
), erhält der Aufruf von\abs
sein Argument in der falschen Form –\l__mymodule_size_tl
es gilt[ \use:c { \tl_use:N \l_keys_choice_tl } ]
, nicht[\big]
. - Wenn ich eine einstufige Erweiterung (d. h.
\tl_set:No
) verwende und[
nach Abschluss der Erweiterung voranstelle,\l__mymodule_size_tl
gilt[ \cs:w \tl_use:N \l_keys_choice_tl \cs_end: ]
, nicht[\big]
. - Wenn ich entweder die
f
oderx
die Erweiterung verwende,\l__mymodule_size_tl
entsteht ein Haufen „Müll“, nicht[\big]
.
Was kann ich tun? Hier ist eine Idee: Verwenden Sie zwei o
Erweiterungen mit etwas Akrobatik dazwischen.
\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 { [ }
Das ist meiner Meinung nach ziemlich hässlich. Kann ich etwas Besseres tun?
Antwort1
Früher gab es ein d
Argument vom Typ - für die doppelte Erweiterung. Es wurde jedoch vor einigen Jahren fallengelassen, da es nur an sehr wenigen Stellen erforderlich war, insbesondere als das Team beschloss, toks
generell keine Register zu verwenden. Soweit ich mich erinnere, expl3
gab es zwei Stellen, an denen wir eine Konstruktion der Form \exp_args:NNo \exp_args:No
oder einer ähnlichen Form verwenden mussten.
Der Grund, warum wir -type-Argumente nicht beibehalten haben, ist zweifach. Erstens möchten wir es möglichst vermeiden, uns auf die Kenntnis der Erweiterungsdetails von Funktionen zu verlassen: Dies ist für die Arbeit auf niedriger Ebene erforderlich, sollte aber idealerweise relativ begrenzt sein. Der andere Grund ist, dass es sehr selten benötigt wird, da wir e-TeX zur Verfügung haben. Der Schlüssel zum Erinnern ist, dass dies uns ermöglicht, die Erweiterung in -type-Kontexten d
zu steuern.x
\tl_set:Nx \l__mymodule_size_tl
{ [ \exp_not:c { \tl_use:N \l_keys_choice_tl } ] }
Obwohl es hier nicht benötigt wird, dokumentieren wir \cs:w
... \cs_end:
für Situationen, in denen genau eine Erweiterung erforderlich ist, sodass Sie Folgendes haben könnten:
\tl_set:No \l__mymodule_size_tl
{ \exp_after:wN [ \cs:w \tl_use:N \l_keys_choice_tl \cs_end: ] }
obwohl ich das hier selbst nicht verwenden würde.
Antwort2
Mein Eindruck ist, dass Sie
\tl_set:Nx \l__mymodule_size_tl
{
[ \exp_not:c { \tl_use:N \l_keys_choice_tl } ]
}
Mit wird x
die Erweiterung \exp_not:c
ausgelöst, sodass das Argument wie immer vollständig erweitert wird, wenn c
beteiligt ist (es ist \csname...\endcsname
); dann wird das resultierende Token nicht erweiterbar gemacht, wenn Sie also haben
size=big
Sie gelangen [\big]
in Ihre Token-Liste.