高阶递归宏一次定义几个类似的宏进行无限循环

高阶递归宏一次定义几个类似的宏进行无限循环

我热衷于分解,讨厌代码重复。因此,我尝试定义一个宏,它为我定义所有常见的数学集命令(\C\N等),并创建了一个递归函数,启发了\slowRomannumeral等等),并从这些命令中创建了一个启发自第 24 页TeX 和 LaTeX 编程笔记

所以我首先做了这个:

\def\defsets#1{\defnextset #1@}
\def\defnextset#1{\ifx @#1 \else
    \expandafter\newcommand\csname #1\endcsname{\mathbb{#1}}
    \expandafter\defnextset
  \fi}
\defsets{RDNZQC}

但是我很快意识到我的数学运算符需要类似的东西,完全相同,只是用 而\DeclareMathOperator不是\newcommand和不带\mathbb,所以我定义了一个\defset命令并尝试使我的主要宏高阶:

\newcommand{\defset}[1]{\expandafter\newcommand\csname #1\endcsname{\mathbb{#1}}}
\def\defsets#1{\defnext\defset #1@}
\def\defnext#1#2{\ifx @#2 \else
    #1#2\relax
    \expandafter\defnext#1
  \fi}
\defsets{RDNZQC}

我检查了很多东西:我把一个\relax否则,由于未知的原因,它会尝试重新定义 expandafter,第一个\newcommand 工作,#1#2应该工作,并且使用\def而不是\newcommand*定义\defset我得到以下错误:

ERROR: Missing \endcsname inserted.

--- TeX said ---
<to be read again> 
                   \let 
l.68 \defsets{RDNZQC}

并添加一个\expandafter与实际当前代码相同的代码\newcommand*(以及与之相同的所有组合):无限循环。

那么如何使该代码工作呢?所以我可以做一个\defop并对我的数学运算符做同样的事情,并使用括号之间的每个运算符命令进行一些代码技巧(因为这实际上目前适用于单个字符)。

答案1

您不能通过一个 跳过多个标记\expandafter。您的问题还有更多解决方案。例如,您可以\let首先设置使用的 def-method:

\def\defset#1{\expandafter\def\csname#1\endcsname{\mathbb{#1}}}

\def\defsets#1{\let\defnextA=\defset \defnext #1@}
\def\defnext#1{\ifx @#1\else
    \defnextA{#1}%
    \expandafter\defnext
  \fi}

\defsets{RDNZQC}

第二:您可以重复 def 方法,#1但多一个\expandafter

\def\defset#1{\expandafter\def\csname#1\endcsname{\mathbb{#1}}}

\def\defsets#1{\defnext\defset #1@}
\def\defnext#1#2{\ifx @#2\else
    #1{#2}%
    \expandafter\defnext\expandafter#1%
  \fi}

\defsets{RDNZQC}

答案2

你需要扩大\fi

\RequirePackage{amsmath}

\makeatletter

\newcommand{\defset}[1]{\expandafter\newcommand\csname #1\endcsname{\mathbb{#1}}}
\def\defsets#1{\defnext\defset #1@}
\def\defnext#1#2{\ifx @#2%
    \expandafter\@gobble
   \else
    #1{#2}%
    \expandafter\@firstofone
   \fi    
    {\defnext#1}}
\defsets{RDNZQ{Zzz}C}


\show\Z
\show\Zzz


\newcommand*{\defop}[1]{\expandafter\DeclareMathOperator\csname #1\endcsname{#1}}

\defnext\defop {Vect}{Spec}@

{\let\protect\show\Vect}

\stop

生产

LaTeX2e <2016/03/31>
Babel <3.9q> and hyphenation patterns for 81 language(s) loaded.
> \Z=\long macro:
->\mathbb {Z}.
l.15 \show\Z

? 
> \Zzz=\long macro:
->\mathbb {Zzz}.
l.16 \show\Zzz

? 
> \Vect =\long macro:
->\qopname \newmcodes@ o{Vect}.
\Vect ->\protect \Vect  

l.23 {\let\protect\show\Vect
                            }
? 

请注意,您需要重新支撑#2{#2}支持多个标记参数。

答案3

问题当然在于\expandafter\defnext#1试图扩展所替换的内容#1而不是预期的内容\fi

如果您讨厌重复代码,那么您一定会喜欢这个,其中\defsets\defops基本上都是单行代码。

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\defsets}{m}
 {
  \tl_map_inline:nn { #1 }
   {
    \cs_new_protected:cpn { ##1 } { \mathbb{##1} }
   }
 }
\NewDocumentCommand{\defops}{m}
 {
  \clist_map_inline:nn { #1 } 
   {
    \galex_declaremathoperator:cn { ##1 } { ##1 }
   }
 }
\cs_set_eq:NN \galex_declaremathoperator:Nn \DeclareMathOperator
\cs_generate_variant:Nn \galex_declaremathoperator:Nn { c }
\ExplSyntaxOff

\defsets{RDNZQC}
\defops{Vect,Spec}

\begin{document}

\texttt{\meaning\R}

\texttt{\meaning\Q}

\texttt{\meaning\Spec}

\texttt{\expandafter\meaning\csname Spec \endcsname}

\end{document}

只有一个\expandafter能表明\Spec做对了。编码部分没有。

我本可以用

\exp_args:Nc \DeclareMathOperator { ##1 } { ##1 }

而不是定义\galex_declaremathoperator:Nn和其变体。但这样一切都更清晰,也符合建议。

在此处输入图片描述

得到同样的结果\@tfor

\makeatletter
%\let\@xp\expandafter % already done by amsmath
\newcommand{\defsets}[1]{%
  \@tfor\next:=#1\do{%
    \@xp\newcommand\csname\next\@xp\endcsname\@xp{\@xp\mathbb\@xp{\next}}%
  }%
}
\newcommand{\defops}[1]{%
  \@tfor\next:=#1\do{%
    \@xp\DeclareMathOperator\csname\next\@xp\endcsname\@xp{\next}%
  }%
}
\makeatother

\defsets{RDNZQC}
\defops{{Vect}{Spec}}

\@tfor函数本质上是变体中技巧的抽象版本\slowRomannumeral:它每次使用在:=和之间传递的标记列表中的一个项目\do,执行\def\next{<item>}(可以是任何标记)。主要区别恰恰在于此:如果我们不希望它被纳入和的定义中,\next我们需要扩展它。因此需要长链。\next\N\expandafter物品在此上下文中是一个单个标记或一个支撑组。

方法\tl_map_inline:nn很多更好,因为当前项目可以“按字面意思”使用#1(因此在定义主体中必须调用它##1)。

答案4

仿佛战斗过后醒来,一切尘埃已落定……

\documentclass{article}
\usepackage{amsmath}
\usepackage{xinttools}


\makeatletter
\newcommand\defsets [1]
   {\xintFor* ##1 in {#1} \do {\@namedef{##1}{\mathbb{##1}}}}
\makeatother

\newcommand\defops [1]
   {\xintFor ##1 in {#1} \do {\expandafter
           \DeclareMathOperator\csname ##1\endcsname{##1}}}


\defsets{RDNZQC}
\defops{Vect, Spec}

\begin{document}

\texttt{\meaning\R}

\texttt{\meaning\Q}

\texttt{\meaning\Spec}

\texttt{\expandafter\meaning\csname Spec \endcsname}

\end{document}

在此处输入图片描述

相关内容