帮我修复这个代码

帮我修复这个代码

我想尝试学习如何一次性定义大量宏。在聊天室问完这个问题后,我收到了来自一位很棒的埃格尔和玩。

这里是指向工作代码的链接。此后,我尝试进行概括,以便函数\definefoo可以定义长度任意的宏,即存在统一的方式来定义\ab\abg等等\abgd……

经过更多讨论后我对其进行了修改。

我希望以下非工作代码也可以作为我想要实现的伪代码:

\documentclass{amsart}
\usepackage{amsmath}
\makeatletter
\def\definefoo#1#2#3#4{%
  \ifx\relax#4%
     \ifx\relax#3%
        \ifx\relax#2%
           \expandafter\def\csname#1#1\endcsname##1{%
           \csname greek#1\endcsname_{##1}}
        \fi
        \expandafter\def\csname#1#2\endscname##1##2{%
        \csname greek#1\endcsname_{##1}%
        \csname greek#2\endcsname_{##2}}
     \fi
      \expandafter\def\csname#1#2#3\endscname##1##2##3{%
      \csname greek#1\endcsname_{##1}%
      \csname greek#2\endcsname_{##2}%
      \csname greek#3\endcsname_{##3}}
  \fi
  \expandafter\def\csname#1#2#3#4\endscname##1##2##3##4{%
  \csname greek#1\endcsname_{##1}%
  \csname greek#2\endcsname_{##2}%
  \csname greek#3\endcsname_{##3}%
  \csname greek#4\endscname_{##4}}
}

\let\greeka\alpha
\let\greekb\beta
\let\greekg\gamma
\let\greekd\delta
\let\greekl\lambda
\let\greekm\mu

\definefoo a\relax\relax\relax
\definefoo ag\relax\relax\relax
\definefoo abg\relax
\definefoo abd\relax
\makeatother
\begin{document}
$\abd{ij}{kl}{mn} \aa{ij}{kl} \aa{kl}$ 
\end{document}

答案1

你需要一些\else分支:

\documentclass{amsart}
\usepackage{amsmath}
\def\definefoo#1#2#3#4{%
  \ifx\relax#4%
    \ifx\relax#3%
      \ifx\relax#2%
         \expandafter\def\csname#1#1\endcsname##1{%
         \csname greek#1\endcsname_{##1}}
      \else
        \expandafter\def\csname#1#2\endcsname##1##2{%
        \csname greek#1\endcsname_{##1}%
        \csname greek#2\endcsname_{##2}}
      \fi
    \else
      \expandafter\def\csname#1#2#3\endcsname##1##2##3{%
      \csname greek#1\endcsname_{##1}%
      \csname greek#2\endcsname_{##2}%
      \csname greek#3\endcsname_{##3}}
    \fi
  \else
    \expandafter\def\csname#1#2#3#4\endcsname##1##2##3##4{%
    \csname greek#1\endcsname_{##1}%
    \csname greek#2\endcsname_{##2}%
    \csname greek#3\endcsname_{##3}%
    \csname greek#4\endcsname_{##4}}
  \fi
}

\let\greeka\alpha
\let\greekb\beta
\let\greekg\gamma
\let\greekd\delta
\let\greekl\lambda
\let\greekm\mu

\definefoo a\relax\relax\relax
\definefoo ag\relax\relax
\definefoo abg\relax
\definefoo abd\relax
\makeatother

\begin{document}
$\abd{ij}{kl}{mn}$

$\ag{ij}{kl}$

$\aa{kl}$
\end{document}

我建议你采用不同的方法。

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\prop_new:N \g_kan_greek_prop
\prop_gput:Nnn \g_kan_greek_prop { a } { alpha }
\prop_gput:Nnn \g_kan_greek_prop { b } { beta }
\prop_gput:Nnn \g_kan_greek_prop { g } { gamma }
\prop_gput:Nnn \g_kan_greek_prop { d } { delta }
%% Add all the equivalences you need


\NewDocumentCommand{\definefoo}{m}
 {
  \kan_definefoo:n { #1 }
 }

\cs_new_protected:Npn \kan_definefoo:n #1
 {
  \int_case:nnn { \tl_count:n { #1 } }
   {
    {1}{ \kan_definefoo_one:n #1 }
    {2}{ \kan_definefoo_two:nn #1 }
    {3}{ \kan_definefoo_three:nnn #1 }
    {4}{ \kan_definefoo_four:nnnn #1 }
   }
   {}
 }

\cs_new_protected:Npn \kan_definefoo_one:n #1
 {
  \cs_new:cpx { S#1 } ##1
   {
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#1} } \sb { ##1 }
   }
 }
\cs_new_protected:Npn \kan_definefoo_two:nn #1 #2
 {
  \cs_new:cpx { S#1#2 } ##1 ##2
   {
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#1} } \sb { ##1 }
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#2} } \sb { ##2 }
   }
 }
\cs_new_protected:Npn \kan_definefoo_three:nnn #1 #2 #3
 {
  \cs_new:cpx { S#1#2#3 } ##1 ##2 ##3
   {
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#1} } \sb { ##1 }
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#2} } \sb { ##2 }
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#3} } \sb { ##3 }
   }
 }
\cs_new_protected:Npn \kan_definefoo_four:nnnn #1 #2 #3 #4
 {
  \cs_new:cpx { S#1#2#3#4 } ##1 ##2 ##3 ##4
   {
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#1} } \sb { ##1 }
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#2} } \sb { ##2 }
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#3} } \sb { ##3 }
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#4} } \sb { ##4 }
   }
 }
\ExplSyntaxOff


\definefoo{abgd}
\definefoo{abd}
\definefoo{ab}

\begin{document}

$\Sabgd{ij}{kl}{mn}{pq}$

$\Sabd{ij}{kl}{mn}$

$\Sab{ij}{kl}$

\end{document}

我认为,与其为了实现“单字母大小写”而将字母加倍,不如使用一个前缀,使已经定义的包更难被找到。


这是另一种方法:定义一个宏\foo,以递归方式从其第一个参数中吃掉一个字符:

\documentclass{article}

\makeatletter
\def\foo#1{\foo@aux#1\@nil}
\def\foo@aux#1#2\@nil{%
  \if\relax\detokenize{#2}\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\do@final@foo{#1}}
  {\do@inner@foo{#1}{#2}}}
\def\do@final@foo#1#2{\csname greek#1\endcsname_{#2}}
\def\do@inner@foo#1#2#3{%
  \csname greek#1\endcsname_{#3}%
  \foo@aux#2\@nil}
\makeatother
\let\greeka\alpha
\let\greekb\beta
\let\greekg\gamma
\let\greekd\delta
\let\greekl\lambda
\let\greekm\mu

\begin{document}
$\foo{ab}{ij}{kl}$

$\foo{a}{ij}$

$\foo{aambd}{ij}{kl}{mn}{pq}{rs}$
\end{document}

在此处输入图片描述


推荐方式

在 LaTeX 中,使用具有可变数量参数的宏并不是最好的方法,因此这里是关于进行更可控的输入的最终建议。

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\foo}{mm}
 {
  \kan_foo:nn { #1 } { #2 }
 }
\seq_new:N \l__kan_symbols_seq
\seq_new:N \l__kan_subscripts_seq

\cs_new_protected:Npn \kan_foo:nn #1 #2
 {
  \seq_set_from_clist:Nn \l__kan_symbols_seq { #1 }
  \seq_set_from_clist:Nn \l__kan_subscripts_seq { #2 }
  \seq_mapthread_function:NNN \l__kan_symbols_seq \l__kan_subscripts_seq
   \__kan_print:nn
 }
\cs_new:Npn \__kan_print:nn #1 #2
 {
  #1\sb{#2}
 }
\ExplSyntaxOff

\begin{document}
$\foo{\alpha,\beta}{ij,kl}$

$\foo{a,\gamma,\delta}{ij,kl,mn}$
\end{document}

该宏\foo以两个列表作为参数;第一个列表的每个元素与第二个列表中的对应元素配对。输入起来可能更无聊,但肯定更清晰。

在此处输入图片描述

相关内容