以下 MWE 是非常我正在尝试开发的更复杂系统的简化版本。因此,界面看起来有点奇怪,我不希望任何人喜欢它目前的形式,我自己也不喜欢。然而,它展示了我正在处理的一些扩展问题。
假设我想为以下任何形式的界面创建一个宏系统
⟨符号⟩ ^ ⟨上索引⟩ _ ⟨下索引⟩ ( ⟨参数⟩ )
为此,我创建了命令\newmathfunctioncommand{#1}
(#1
命令名称不带反斜杠)。这定义了一些用于存储能力、索引和参数的标记列表,以及\#1
带有接口的命令
\#1 { ⟨symbol⟩ } [ ⟨upper index⟩ ] [ ⟨lower index⟩ ] { ⟨argument⟩ (optional argument) } [ ⟨output math function⟩ ]
这应该打印出⟨symbol⟩ ^ ⟨upper index⟩ _ ⟨lower index⟩ ( ⟨argument⟩ )
如上所示的行。然后它需要一个额外的可选参数⟨output math function⟩
。这应该包含另一个数学函数命令的名称,以包装函数的最终值\#1
,以便它本身成为一个数学函数。换句话说,它应该允许如下接口:
\newmathfunctioncommand{fun}
\newmathfunctioncommand{otherfun}
$\fun{f}[i][j]$ % Should output f^{i}_{j}
$\fun{f}[i][j]{x}$ % Should output f^{i}_{j}(x)
$\fun{f}[\fun{g}{x}]{t}$ % Should output f^{g(x)}(t)
$\fun{f}[i][j]{x}[otherfun]$ % Should output \otherfun{ f^{i}_{j}(x) }
$\fun{f}[i][j]{x}[otherfun]{t}$
% Should output \otherfun{ f^{i}_{j}(x) }{t},
% i.e., f^{i}_{j}(x)(t)
这样做的目的是允许函数的值是其他函数,这是数学中一个众所周知的现象。然而,这是我无法工作的系统的一部分。出错的代码是包含在标签中的代码<code that does not work>
。做工作在标签中<code that does work>
。此工作代码实现了除输出函数系统之外的所有内容。有人可以修复这个扩展问题吗?
请注意,使用的原因\group_begin: ... \group_end:
是为了允许像表达式那样\fun{f}[\fun{g}{x}]{t}
不会导致无限循环。
我知道这个 MWE 中的某些代码部分看起来很荒谬,例如,输出函数设置时没有反斜杠。我要求你保留这个系统,因为它们在我真正试图创建的更复杂的设置中更有意义。此外,为了保持代码简短,这个版本的代码中删除了很多东西,例如,控制括号的大小。
\documentclass{article}
\usepackage{amsmath,xparse}
\ExplSyntaxOn
\tl_new:N\l_mathfunction_temp
\cs_set:Npn\g_mathfunction_identity:n#1 { #1 } % the identity function
\DeclareDocumentCommand\newmathfunctioncommand{m}
{
% This defines the command \⟨#1⟩. First we define some token lists
% to store the data of upper index, lower index etc. in.
\tl_new:c { g_mathfunction_#1_upper_index }
\tl_new:c { g_mathfunction_#1_lower_index }
\tl_new:c { g_mathfunction_#1_argument }
\tl_new:c { g_mathfunction_#1_output_function }
\tl_set:cn { g_mathfunction_#1_output_function } { g_mathfunction_identity:n }
% This will be the default output function if none else is given
\exp_args:Nc\DeclareDocumentCommand{#1}{moogo}{
\group_begin:
\IfNoValueTF { ##2 } % If ##2 is non-empty, set upper index token list
% to that value
{
% do nothing
}
{
\tl_set:cn { g_mathfunction_#1_upper_index } { \exp_not:n { ##2 } }
}
\IfNoValueTF { ##3 } % If ##3 is non-empty, set lower index token list
% to that value
{
% do nothing
}
{
\tl_set:cn { g_mathfunction_#1_lower_index } { \exp_not:n { ##3 } }
}
\IfNoValueTF { ##4 } % If ##4 is non-empty, set argument token list
% to that value
{
% do nothing
}
{
\tl_set:cn { g_mathfunction_#1_argument } {
\exp_not:n { ##4 }
}
}
\IfNoValueTF { ##5 } % If ##5 is non-empty, set output function
% token list to that value.
{
% do nothing
}
{
\tl_set:cn { g_mathfunction_#1_output_function } { \exp_not:n { ##5 } }
}
%
%
%
\tl_set:Nx\l_mathfunction_temp % Store output data in a temporary
% token list
{
\exp_not:n { ##1 }
\tl_if_empty:cTF { g_mathfunction_#1_upper_index }
{
% do nothing
}
{
\sp { \use:c { g_mathfunction_#1_upper_index } }
}
\tl_if_empty:cTF { g_mathfunction_#1_lower_index }
{
% do nothing
}
{
\sb { \use:c { g_mathfunction_#1_lower_index } }
}
\tl_if_empty:cTF { g_mathfunction_#1_argument }
{
% do nothing
}
{
(\use:c { g_mathfunction_#1_argument } )
}
}
%
% Now if the argument has a value, and only in this case, set
% the command \l_mathfunction_output_command:n to be equal
% to the output math function command.
%
\tl_if_empty:cTF { g_mathfunction_#1_argument }
{
\cs_set_eq:NN
\l_mathfunction_output_command:n
\g_mathfunction_identity:n
}
{
\exp_args:Nno\cs_set_eq:cc
{ l_mathfunction_output_command:n }
{ \use:c { g_mathfunction_#1_output_function } }
}
%
%
% Now finally it is time to render the actual output
%
% <code that does not work>
\exp_args:NNo
\exp_args:NNV
\group_end:
\l_mathfunction_output_command:n
{ \l_mathfunction_temp }
% </code that does not work>
%
%
% <code that does work>
% \exp_args:NV
% \group_end:
% \l_mathfunction_temp
% </code that does work>
}
}
\DeclareDocumentCommand\mathfunctionsetup{moogo}
% a command to setup the arguments
% globally.
{
\IfNoValueTF { #2 }
{
% do nothing
}
{
\tl_set:cn { g_mathfunction_#1_upper_index } { \exp_not:n { #2 } }
}
\IfNoValueTF { #3 }
{
% do nothing
}
{
\tl_set:cn { g_mathfunction_#1_lower_index } { \exp_not:n { #3 } }
}
\IfNoValueTF { #4 }
{
% do nothing
}
{
\tl_set:cn { g_mathfunction_#1_argument } {
\exp_not:n { #4 }
}
}
\IfNoValueTF { #5 }
{
% do nothing
}
{
\tl_set:cn { g_mathfunction_#1_output_function } { \exp_not:n { #5 } }
}
}
\ExplSyntaxOff
\begin{document}
\newmathfunctioncommand{fun}
\newmathfunctioncommand{otherfun}
$\fun{f}[i][j]$ % Should output f^{i}_{j}
$\fun{f}[i][j]{x}$ % Should output f^{i}_{j}(x)
$\fun{f}[\fun{g}{x}]{t}$ % Should output f^{g(x)}(t)
$\fun{f}[i][j]{x}[otherfun]$ % Should output \otherfun{ f^{i}_{j}(x) }
$\fun{f}[i][j]{x}[otherfun]{t}$
% Should output \otherfun{ f^{i}_{j}(x) }{t},
% i.e., f^{i}_{j}(x)(t)
\mathfunctionsetup{fun}[a][b][otherfun]
$\fun{g}{x}{t}$ % Should output \otherfun { g^{a}_{b}(x) } { t },
% i.e., g^{i}_{j}(x)(t)
\mathfunctionsetup{fun}[a][b][fun]
$\fun{g}{x}[p][q]{r}$ % Should output \fun { g^a_b(x) }[p][q]{r},
% i.e., g^{a}_{b}(x) ^{p}_{q}(r)
\end{document}
答案1
语法可能会更清楚吗\fun{f}[a][b](x)
?
无论如何,这是一个解决方案。唯一的变化是可选函数参数在开头\fun[otherfun]{f}[a][b]{t}{x}
应该是给出函数的方式。
请注意,您的文档中有很多内容可以纠正(变量名称、函数名称、用法TF
、与扩展有关的一些不必要的内容等)。
唯一不正确的是最后一个输出,因为我不知道背后的逻辑,我不知道如何确保最后一个下标上标只在正确的情况下添加。如果你添加逻辑,我可以修正我的代码。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\tl_new:N \l_gaussler_tmp_tl
\NewDocumentCommand \newmathfunctioncommand { m }
{
\gaussler_newmfcmd:c { #1 }
}
\NewDocumentCommand \mathfunctionsetup { m o o g o }
{
\IfValueT {#2} { \tl_set:cn { l_gaussler_mf_ \tl_to_str:n {#1} _sp_tl } { #2 } }
\IfValueT {#3} { \tl_set:cn { l_gaussler_mf_ \tl_to_str:n {#1} _sb_tl } { #3 } }
\IfValueT {#4} { \tl_set:cn { l_gaussler_mf_ \tl_to_str:n {#1} _arg_tl } { #4 } }
\IfValueT {#5} { \cs_set:cpn { gaussler_mf_ \tl_to_str:n {#1} _use:w } { \use:c { #5 } } }
}
\cs_new_protected:Npn \gaussler_newmfcmd:N #1
{
\tl_new:c { l_gaussler_mf_ \cs_to_str:N #1 _arg_tl }
\tl_new:c { l_gaussler_mf_ \cs_to_str:N #1 _sp_tl }
\tl_new:c { l_gaussler_mf_ \cs_to_str:N #1 _sb_tl }
\cs_new:cpn { gaussler_mf_ \cs_to_str:N #1 _use:w } { \use:n }
\NewDocumentCommand #1 { o m o o g }
{
\group_begin:
\IfValueT {##1}
{ \cs_set:cpn { gaussler_mf_ \cs_to_str:N #1 _use:w } { \use:c { ##1 } } }
\IfValueT {##3}
{ \tl_set:cn { l_gaussler_mf_ \cs_to_str:N #1 _sp_tl } { ##3 } }
\IfValueT {##4}
{ \tl_set:cn { l_gaussler_mf_ \cs_to_str:N #1 _sb_tl } { ##4 } }
\IfValueT {##5}
{ \tl_set:cn { l_gaussler_mf_ \cs_to_str:N #1 _arg_tl } { ##5 } }
\tl_set:Nx \l_gaussler_tmp_tl
{
\IfNoValueTF {##5}
{ \exp_not:N \use:n }
{ \use:c { gaussler_mf_ \cs_to_str:N #1 _use:w } }
{
\exp_not:n { ##2 }
\tl_if_empty:cF { l_gaussler_mf_ \cs_to_str:N #1 _sp_tl }
{ \sp{ \tl_use:c { l_gaussler_mf_ \cs_to_str:N #1 _sp_tl } } }
\tl_if_empty:cF { l_gaussler_mf_ \cs_to_str:N #1 _sb_tl }
{ \sb{ \tl_use:c { l_gaussler_mf_ \cs_to_str:N #1 _sb_tl } } }
\tl_if_empty:cF { l_gaussler_mf_ \cs_to_str:N #1 _arg_tl }
{ ( \tl_use:c { l_gaussler_mf_ \cs_to_str:N #1 _arg_tl } ) }
}
}
\exp_last_unbraced:NV
\group_end:
\l_gaussler_tmp_tl
}
}
\cs_generate_variant:Nn \gaussler_newmfcmd:N { c }
\ExplSyntaxOff
\begin{document}
\newmathfunctioncommand{fun}
\newmathfunctioncommand{otherfun}
$\fun{f}[i][j]$ % Should output f^{i}_{j}
$\fun{f}[i][j]{x}$ % Should output f^{i}_{j}(x)
$\fun{f}[\fun{g}{x}]{t}$ % Should output f^{g(x)}(t)
$\fun[otherfun]{f}[i][j]{x}$ % Should output \otherfun{ f^{i}_{j}(x) }
$\fun[otherfun]{f}[i][j]{x}{t}$
% Should output \otherfun{ f^{i}_{j}(x) }{t},
% i.e., f^{i}_{j}(x)(t)
\mathfunctionsetup{fun}[a][b][otherfun]
$\fun{g}{x}{t}$ % Should output \otherfun { g^{a}_{b}(x) } { t },
% i.e., g^{i}_{j}(x)(t)
\mathfunctionsetup{fun}[a][b][fun]
$\fun{g}{x}[p][q]{r}$ % Should output \fun { g^a_b(x) }[p][q]{r},
% i.e., g^{a}_{b}(x) ^{p}_{q}(r)
\end{document}