def 的问题

def 的问题

我在 LaTeX 中创建了以下宏:

\def\twomate(#1,#2,#3,#4){\begin{pmatrix}#1&#2\\#3&#4\end{pmatrix}}
\def\pwr(#1){^{#1}}
\def\twoclmn(#1,#2){\begin{pmatrix}#1\\#2\end{pmatrix}}

其中\twomate是一个 2x2 矩阵,\twoclmn创建一个 2x1 列向量,并且\pwr是一个将参数提升到幂的命令。但是,如果我尝试执行以下操作:

$$\twomate(3e\pwr(-3t),e\pwr(2t),-e\pwr(-3t),-2e\pwr(2t) )$$

我收到错误。但是,如果我用非命令的内容替换最后一个条目def

$$\twomate(3e\pwr(-3t),e\pwr(2t),-e\pwr(-3t),5 )$$

文档成功编译。此外,以下内容无法成功编译:

$$\twoclmn(\frac{6}{25}e\pwr(2t)-\frac15te\pwr(2t),-\frac{2}{25}e\pwr(2t) + \frac25 t e\pwr(2t))$$

但下面确实如此:

$$\twoclmn(\frac{6}{25}e^{2t}-\frac15te^{2t},-\frac{2}{25}e^{2t} + \frac25 t e^{2t})$$

所以问题似乎出在嵌套\def命令上。我怎样才能嵌套\def命令而不引起编译器的抱怨?

答案1

您可以使用xparse它来完成这项工作,因为r参数类型负责嵌套。

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

\NewDocumentCommand{\twomate}{>{\SplitArgument{3}{,}}r()}{%
  \maketwomate#1%
}
\NewDocumentCommand{\maketwomate}{mmmm}{%
  \begin{pmatrix}#1&#2\\#3&#4\end{pmatrix}%
}
\NewDocumentCommand{\pwr}{r()}{^{#1}}

\begin{document}

\[
\twomate(3e\pwr(-3t),e\pwr(2t),-e\pwr(-3t),-2e\pwr(2t) )
\]

\end{document}

但是,使用()作为分隔符似乎不是一个好主意。以下内容同样清晰,并且在前端语法着色方面表现更好。

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

\NewDocumentCommand{\twomate}{>{\SplitArgument{3}{,}}m}{%
  \maketwomate#1%
}
\NewDocumentCommand{\maketwomate}{mmmm}{%
  \begin{pmatrix}#1&#2\\#3&#4\end{pmatrix}%
}
\NewDocumentCommand{\pwr}{m}{^{#1}}

\begin{document}

\[
\twomate{3e\pwr{-3t},e\pwr{2t},-e\pwr{-3t},-2e\pwr{2t}}
\]

\end{document}

在此处输入图片描述

答案2

您的\def包含一个非常具体的序列,定义为参数文本:

%           1   2   3   4   5
\def\twomate(<1>,<2>,<3>,<4>){ ... }
%           ^   ^   ^   ^   ^
%           │   │   │   │   │
%           │   └ comma ┘   │
%           └─── bracket ───┘

此参数文本按顺序精确匹配(几乎像先到先得的样式),以提取四个参数、 和<1><2>以下是使用上述符号抓取元素的方法:<3><4>\twomate

%       1           2         3           4          5
\twomate(3e\pwr(-3t),e\pwr(2t),-e\pwr(-3t),-2e\pwr(2t))
%       ^           ^         ^           ^          ^
%       │           │         │           │          │
%       │           └────── comma ────────┘          │
%       └───────────────── bracket ──────────────────┘

应该清楚的是,最后一个括号)没有被正确捕获\pwr。解决这个问题的方法是隐藏\pwr(.)\twomate

\documentclass{article}

\usepackage{amsmath}

\def\twomate(#1,#2,#3,#4){\begin{pmatrix}#1&#2\\#3&#4\end{pmatrix}}
\def\pwr(#1){^{#1}}

\begin{document}

\[
  \twomate(3e\pwr(-3t),e\pwr(2t),-e\pwr(-3t),{-2e\pwr(2t)})
\]

\end{document}

这只能暂时解决问题。如果嵌套元素,由于参数文本模式匹配,您会遇到类似的问题。通常,使用{...对参数进行分组更安全}

答案3

TeX 的分隔参数解析没有正确考虑嵌套。因此,如果您调用\twomate(3e\pwr(-3t), ...),则最终的)for\twomate不会在该行的末尾找到,而是在 的末尾找到\pwr(-3t)。不正确的 then 调用\pwr会导致麻烦。

要隐藏命令的嵌套调用,请将它们分成{ ... }几组(尽管这可能违背了目的):

\documentclass{article}
\usepackage{amsmath}

\def\twomate(#1,#2,#3,#4){\begin{pmatrix}#1&#2\\#3&#4\end{pmatrix}}
\def\pwr(#1){^{#1}}
\def\twoclmn(#1,#2){\begin{pmatrix}#1\\#2\end{pmatrix}}

\begin{document}
\[ \twomate({3e\pwr(-3t)},{e\pwr(2t)},{-e\pwr(-3t)},{-2e\pwr(2t)}) \]
\end{document}

在此处输入图片描述

顺便说一句,不要使用$$ ... $$显示数学环境,而是使用 LaTeX 或amsmath类似的变体\[ ... \]

答案4

以下是如何定义需要括号中逗号分隔参数的宏。代码将任何标准 LaTeX 命令(具有非分隔参数的宏)转换为一个需要(..., ..., ...)输入语法的命令。使用时,参数的数量必须是宏所期望的数量,没有错误检查。

嵌套有效,我们将使用这种输入进行测试:

\foo(\Bar(3,5,7),\Bar(9,\foo(a,\Bar(W,X,Y),c,d),13),\Bar(15,17,19),\Bar(21,23,25))

请注意,输入中的空格没有特殊处理,并且在某些情况下可能会出现一些括号剥离。

由于这一切都纯粹是通过扩展来实现的,因此可扩展的命令仍然是可扩展的命令。

重要的:为了更充分地实现与“函数符号”的类比,宏\foo(\a, \b, \c)应该第一的在执行任何操作之前完全扩展\a, \b, (如果只是为了效率的原因)。但这会从一开始就将此类构造限制在可扩展宏的范围内。此外,只有新的原语允许(轻松)进行这种完全扩展。否则,可以使用一些受控扩展将宏限制为仅“第一个完全”可扩展的宏(如果宏扩展为以空格标记开头的内容,则会出现问题。)无论如何,在这里我没有在应用宏之前添加 的自动扩展,我更倾向于 TeX 中诸如 之类的常见宏扩展。\c\expanded\romannumeral-`Q\a, \b, \c\foo\foo{\a}{\b}{\c}

\documentclass{article}
\usepackage{amsmath}

% copy over some utility code from package xintexpr
\catcode`_ 11

\makeatletter
\let\xint_c_mone\m@ne
\let\xint_c_\z@
\let\xint_c_i\@ne
\long\def\xint_bye #1\xint_bye {}%
\makeatother
% THE \XINT_isbalanced_... MACROS COPIED OVER FROM XINTEXPR CODE MADE
% HERE ALL \long
% %    \end{macrocode}
% \subsubsection{\csh{XINT_isbalanced_a} for \cshnolabel{XINT_expr_onliteral_seq_a}}
% \lverb|Expands to \xint_c_mone in case a closing ) had no opening ( matching
% it, to \@ne if opening ( had no closing ) matching it, to \z@ if expression
% was balanced.|
%    \begin{macrocode}
% use as \XINT_isbalanced_a \relax #1(\xint_bye)\xint_bye
\long\def\XINT_isbalanced_a #1({\XINT_isbalanced_b #1)\xint_bye }%
\long\def\XINT_isbalanced_b #1)#2%
   {\xint_bye #2\XINT_isbalanced_c\xint_bye\XINT_isbalanced_error }%
%    \end{macrocode}
% \lverb|if #2 is not \xint_bye, a ) was found, but there was no (. Hence error -> -1|
%    \begin{macrocode}
\long\def\XINT_isbalanced_error #1)\xint_bye {\xint_c_mone}%
%    \end{macrocode}
% \lverb|#2 was \xint_bye, was there a ) in original #1?|
%    \begin{macrocode}
\long\def\XINT_isbalanced_c\xint_bye\XINT_isbalanced_error #1%
    {\xint_bye #1\XINT_isbalanced_yes\xint_bye\XINT_isbalanced_d #1}%
%    \end{macrocode}
% \lverb|#1 is \xint_bye, there was never ( nor ) in original #1, hence OK.|
%    \begin{macrocode}
\long\def\XINT_isbalanced_yes\xint_bye\XINT_isbalanced_d\xint_bye )\xint_bye {\xint_c_ }%
%    \end{macrocode}
% \lverb|#1 is not \xint_bye, there was indeed a ( in original #1. We check if
% we see a ). If we do, we then loop until no ( nor ) is to be found.|
%    \begin{macrocode}
\long\def\XINT_isbalanced_d #1)#2%
   {\xint_bye #2\XINT_isbalanced_no\xint_bye\XINT_isbalanced_a #1#2}%
%    \end{macrocode}
% \lverb|#2 was \xint_bye, we did not find a closing ) in original #1. Error.|
%    \begin{macrocode}
\long\def\XINT_isbalanced_no\xint_bye #1\xint_bye\xint_bye {\xint_c_i }%

% NEW EXPANDABLE UTILITY

\long\def\applyfunction #1#2)%
{%
    \ifcase\XINT_isbalanced_a \relax #1#2)(\xint_bye)\xint_bye
           \expandafter\applyfunction_b
        \or\expandafter\applyfunction_again
      \else\expandafter\we_are_doomed
    \fi {#1#2}%
}%
\long\def\applyfunction_again #1{\applyfunction {#1)}}%
\long\def\my_bbye #1\my_bbye {}%
\long\def\applyfunction_b #1{\applyfunction_c #1,\my_bbye,}%
\long\def\applyfunction_c #1({\applyfunction_d #1{}{}}%
% we will take care of brace removal another day
\long\def\applyfunction_d #1#2#3#4,%
{%
    \ifcase\XINT_isbalanced_a \relax #3#4(\xint_bye)\xint_bye
           \expandafter\applyfunction_e
        \or\expandafter\applyfunction_d_again
      \else\expandafter\we_are_doomed
    \fi #1{#2}{#3}{#4}%
}%
\long\def\applyfunction_d_again #1#2#3#4%
{%
    \applyfunction_d #1{#2}{#3#4,}%
}%
\long\def\applyfunction_e #1#2#3#4%
{%
    \my_bbye#4\applyfunction_finish\my_bbye
    \applyfunction_g #1{#2}{#3#4}%
}%
\long\def\applyfunction_g #1#2#3{\applyfunction_d #1{#2{#3}}{}}%
\long\def\applyfunction_finish\my_bbye\applyfunction_g #1#2#3{#1#2}%

\catcode`_ 8

%% USAGE
% to define a "function" to be used as \foo(a,b,c,...),
% we need a \foomacro which uses standard non-delimited parameters,
% thus e.g. defined via \newcommand, and then one only needs
% \newcommand\foo{\applyfunction\foomacro}
% to get a \foo to be used with parentheses.

\newcommand\twomate{\applyfunction\twomatemacro}
\newcommand\pwr{\applyfunction\pwrmacro}
\newcommand\twoclmn{\applyfunction\twoclmnmacro}

% define here the **non-delimited** auxiliary macros
\newcommand\twomatemacro[4]{\begin{pmatrix}#1&#2\\#3&#4\end{pmatrix}}
\newcommand\pwrmacro[1]{^{#1}}
\newcommand\twoclmnmacro[2]{\begin{pmatrix}#1\\#2\end{pmatrix}}

%% TESTING NESTING
\newcommand\foo{\applyfunction\foomacro}
\newcommand\foomacro[4]{\left[#1+#2+#3+#4\right]}
\let\Bar\relax
\newcommand\Bar{\applyfunction\Barmacro}
\newcommand\Barmacro[3]{\left(#1*#2*#3\right)}

\delimiterfactor1001

\begin{document}

\[
  \twomate(3e\pwr(-3t),e\pwr(2t),-e\pwr(-3t),-2e\pwr(2t))
\]
\[
  \twoclmn(\frac{6}{25}e\pwr(2t)-\frac15te\pwr(2t),-\frac{2}{25}e\pwr(2t)
  + \frac25 t e\pwr(2t))
\]
\[\foo(\Bar(3,5,7),\Bar(9,\foo(a,\Bar(W,X,Y),c,d),13),\Bar(15,17,19),\Bar(21,23,25))\]
\end{document}

在此处输入图片描述

相关内容