我在 LaTeX 中创建了以下宏:
\def\twomate(#1,#2,#3,#4){\begin{pmatrix}#1\\#3\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\\#3\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\\#3\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\\#3\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\\#3\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\\#3\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}