寻求有关宏 \DefineOperator 的帮助

寻求有关宏 \DefineOperator 的帮助

我正在尝试构建一个\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}

在此处输入图片描述

相关内容