我正在尝试构建一个\DefineOperator
用于一次定义多个运算符的命令,可以像这样使用:
\DefineOperator { ord, card, car, disc }
\DefineOperator { id, Id, Ker, Image = Im } [ style = \mathsf ]
\DefineOperator*{ Lim, Max, Min } [ style = \mathsf ]
\DefineOperator { Set, Mat, Grp, Top } [ style = \mathbf ]
目前,基本界面可以使用,但是它的选项style = ...
有点问题:我不知道如何传递价值\l__projlib_math_operator_style_tl
而不是宏本身\DeclareMathOperator
,因此所有运算符都共享最后指定的样式。如何修复此行为?
另外,我觉得我对\exp_after:wN
或\exp_args:Ne
的用法\DeclareMathOperator
不太优雅,但想不出更好的办法。你对此有什么建议吗?
以下是 MWE。提前感谢大家的帮助~
\documentclass{article}
\usepackage{mathtools}
\ExplSyntaxOn
\cs_generate_variant:Nn \msg_warning:nnn { nne }
\msg_new:nnn { projlib-math }
{ operator-not-define }
{ The~math~operator~"#1"~cannot~be~defined,~a~command~with~the~same~name~has~already~existed. }
\tl_new:N \l__projlib_math_operator_style_tl
\keys_define:nn { projlib-math-operator }
{
, style .tl_set:N = \l__projlib_math_operator_style_tl
, unknown .code:n = {}
}
\cs_new_protected:Nn \projlib_math_define_operator:nnn
% #1 is a bool for star or empty
% #2 is a list of operators
% #3 is the option
{
\keys_set:nn { projlib-math-operator } { #3 }
\clist_map_inline:nn { #2 }
{
\str_if_in:nnTF { ##1 } { = }
{
\seq_set_split:Nnn \l_tmpa_seq { = } { ##1 }
\cs_if_exist:cTF { \seq_item:Nn \l_tmpa_seq { 1 } }
{
\msg_warning:nne { projlib-math } { operator-not-define } { \seq_item:Nn \l_tmpa_seq { 1 } }
}
{
\bool_if:NTF #1
{
\exp_after:wN \DeclareMathOperator \exp_after:wN * \exp_after:wN { \cs:w \seq_item:Nn \l_tmpa_seq { 1 } \cs_end: } { \l__projlib_math_operator_style_tl { \seq_item:Nn \l_tmpa_seq { 2 } } }
}
{
\exp_args:Ne \DeclareMathOperator { \cs:w \seq_item:Nn \l_tmpa_seq { 1 } \cs_end: } { \l__projlib_math_operator_style_tl { \seq_item:Nn \l_tmpa_seq { 2 } } }
}
}
}
{
\cs_if_exist:cTF { ##1 }
{
\msg_warning:nnn { projlib-math } { operator-not-define } { ##1 }
}
{
\bool_if:NTF #1
{
\exp_after:wN \DeclareMathOperator \exp_after:wN * \exp_after:wN { \cs:w ##1 \cs_end: } { \l__projlib_math_operator_style_tl { ##1 } }
}
{
\exp_args:Ne \DeclareMathOperator { \cs:w ##1 \cs_end: } { \l__projlib_math_operator_style_tl { ##1 } }
}
}
}
}
}
\NewDocumentCommand \DefineOperator { s O{} m O{} }
{
\tl_if_blank:nTF { #2 }
{
\projlib_math_define_operator:nnn { #1 } { #3 } { #4 }
}
{
\projlib_math_define_operator:nnn { #1 } { #3 } { #2 }
}
}
\ExplSyntaxOff
\DefineOperator { id, Id, Ker, Image = Im } [ style = \mathsf ]
\DefineOperator*{ Lim, Max } [ style = \mathbf ]
\begin{document}
\( \id_A \)
\( \Lim_{n\to \infty} \)
\[
\Lim_{n\to \infty}
\]
\[
\Max_A
\]
\( \Id_A, \Image \)
\end{document}
答案1
您想为风格和评估设置不同的关键系列。
采用间接方法:强制参数以键值形式吸收,其中所有键都是未知的。相应的代码填充可映射的属性列表。每个属性都有所需的命令名称作为键,所需的符号作为值(或没有)。
最后我们可以测试值是否为空,并将键用作命令名称和符号。
利用辅助函数的两个合适变体,我们可以扩展它style
(如果不为空)。
\documentclass{article}
\usepackage{amsmath}
\ExplSyntaxOn
\NewDocumentCommand{\DefineOperator}{ s O{} m }
{
\keys_set:nn { projlib-math-operator } { style=, #2 }
\IfBooleanTF { #1 }
{
\projlib_math_define_operator:nnn { * } { #2 } { #3 }
}
{
\projlib_math_define_operator:nnn { } { #2 } { #3 }
}
}
\prop_new:N \l__projlib_math_operator_prop
\keys_define:nn { projlib-math-operator }
{
style .tl_set:N = \l__projlib_math_operator_style_tl,
}
\keys_define:nn { projlib-math-operator-aux }
{
unknown .code:n = \prop_put:NVn \l__projlib_math_operator_prop \l_keys_key_str { #1 },
}
\cs_new_protected:Nn \projlib_math_define_operator:nnn
{
\prop_clear:N \l__projlib_math_operator_prop
\keys_set:nn { projlib-math-operator-aux } { #3 }
\prop_map_inline:Nn \l__projlib_math_operator_prop
{
\tl_if_empty:nTF { ##2 }
{
\__projlib_math_define_operator:nnn { #1 } { ##1 } { ##1 }
}
{
\__projlib_math_define_operator:nnn { #1 } { ##1 } { ##2 }
}
}
}
\cs_new_protected:Nn \__projlib_math_define_operator:nnn
{
\tl_if_empty:NTF \l__projlib_math_operator_style_tl
{% no style
\__projlib_math_define_operator_aux:cnn { #2 } { #3 } { #1 }
}
{% style
\__projlib_math_define_operator_aux:con { #2 } { \l__projlib_math_operator_style_tl { #3 } } { #1 }
}
}
\cs_new_protected:Nn \__projlib_math_define_operator_aux:Nnn
{% #1 is the command
% #2 is the desired symbol
% #3 is either * or empty
\DeclareMathOperator #3 #1 { #2 }
}
\cs_generate_variant:Nn \__projlib_math_define_operator_aux:Nnn { cnn, con }
\ExplSyntaxOff
\DefineOperator { ord, card, car, disc }
\DefineOperator [style=\mathsf]{ id, Id, Ker, Image = Im }
\DefineOperator*[style=\mathsf]{ Lim, Max, Min }
\DefineOperator [style=\mathbf]{ Set, Mat, Grp, Top }
\begin{document}
$\ord\card\car\disc\id\Id\Ker\Image\Lim\Max\Min\Set\Mat\Grp\Top$
\end{document}
数学注释。我留下了最后一组,但类别的符号是不是运算符。它们应该是普通符号。
答案2
我不知道这是否被认为更优雅,但你可以,例如,使用模式表达式的级联
\exp_args:Nn⟨expansion-type⟩ \use:n
{⟨tokens not to be touched by the \exp_args:Nn..-command⟩}
{⟨tokens to be expanded according to expansion-type⟩}
,其中⟨tokens not to be touched by the \exp_args:Nn..-command⟩
和⟨tokens to be expanded according to expansion-type⟩
也可以包含这样的表达式。
这样,您可以根据需要扩展/提取(嵌套的)宏参数(的组件):
\documentclass{article}
\usepackage{mathtools}
\ExplSyntaxOn
\msg_new:nnn { projlib-math }
{ operator-not-define }
{ The~math~operator~"#1"~cannot~be~defined,~a~command~with~the~same~name~has~already~existed. }
\tl_new:N \l__projlib_math_operator_style_tl
\keys_define:nn { projlib-math-operator }
{
, style .tl_set:N = \l__projlib_math_operator_style_tl
, unknown .code:n = {}
}
\cs_new_protected:Nn \projlib_math_define_operator:nnn
% #1 is a bool for star or empty
% #2 is a list of operators
% #3 is the option
{
\keys_set:nn { projlib-math-operator } { #3 }
\clist_map_inline:nn { #2 }
{
\str_if_in:nnTF { ##1 } { = }
{
\seq_set_split:Nnn \l_tmpa_seq { = } { ##1 }
\cs_if_exist:cTF { \seq_item:Nn \l_tmpa_seq { 1 } }
{
\exp_args:Nne \use:n
{ \msg_warning:nnn { projlib-math } { operator-not-define } }
{ \seq_item:Nn \l_tmpa_seq { 1 } }
}
{
\bool_if:NTF #1
{
\exp_args:Nnf \use:n
{ \exp_args:Nnc \use:n {\DeclareMathOperator*} { \seq_item:Nn \l_tmpa_seq { 1 } } }
}
{
\exp_args:Nnf \use:n
{ \exp_args:Nc \DeclareMathOperator { \seq_item:Nn \l_tmpa_seq { 1 } } }
}
% This is the f-argument of \exp_args:Nnf :
{ \exp_args:Nne \use:n
{ \exp_args:NnV \use:nn
{ \exp_stop_f: }
{ \l__projlib_math_operator_style_tl }
}
{ \seq_item:Nn \l_tmpa_seq { 2 } }
}
}
}
{
\cs_if_exist:cTF { ##1 }
{
\msg_warning:nnn { projlib-math } { operator-not-define } { ##1 }
}
{
\bool_if:NTF #1
{
\exp_args:Nnf \use:n
{ \exp_args:Nnc \use:n {\DeclareMathOperator*} {##1} }
}
{
\exp_args:Nnf \use:n
{ \exp_args:Nc \DeclareMathOperator {##1} }
}
% This is the f-argument of \exp_args:Nnf :
{ \exp_args:NnV \use:nn
{ \exp_stop_f: }
{ \l__projlib_math_operator_style_tl } { ##1 }
}
}
}
}
}
\NewDocumentCommand \DefineOperator { s O{} m O{} }
{
\tl_if_blank:nTF { #2 }
{
\projlib_math_define_operator:nnn { #1 } { #3 } { #4 }
}
{
\projlib_math_define_operator:nnn { #1 } { #3 } { #2 }
}
}
\ExplSyntaxOff
\DefineOperator { id, Id, Ker, Image = Im } [ style = \mathsf ]
\DefineOperator*{ Lim, Max } [ style = \mathbf ]
\begin{document}
\( \id_A \)
\( \Lim_{n\to \infty} \)
\[
\Lim_{n\to \infty}
\]
\[
\Max_A
\]
\( \Id_A, \Image \)
\end{document}