我正在 LaTeX2e 中定义一个宏来编写函数声明。
我希望宏具有三个强制参数:函数名称(vg f
)、它所采用的变量类型的描述(vg x
)以及定义函数的空间(vg \mathbb R
),以及三个可选参数:域(如果域与陪域不同)、应用于其变量的函数的书写以及函数的赋值/含义。
为了在使用宏时更加清楚,我决定采用以下结构:
\funcdef{functionName}{variables}[domain]{codomain}[notation][definition]
为了避免最后两个可选元素产生歧义,当给出符号但没有定义时,其形式为:
\funcdef{functionName}{variables}[domain]{codomain}[notation]
当给出定义但没有符号时:
\funcdef{functionName}{variables}[domain]{codomain}*[definition]
我提供了以下代码(声明和示例),它可以运行,但似乎有点太复杂:
\documentclass{article}
\makeatletter
\newcommand\funcdef[2]{\def\func@name{#1}\def\func@var{#2}%
\begin{array}{r@{\ }c@{\,}c@{\,}l}#1:\func@dom}
\newcommand\func@dom[2][\@empty]{&\ifx#1\@empty#2\else#1\fi%
&\to\\&\func@var&\mapsto&\func@use}
\newcommand\func@use{\@ifstar\func@use@\func@usei}
\newcommand\func@use@{\func@name(\func@var)\func@def}
\newcommand\func@usei[1][\@empty]{\ifx#1\@empty\func@name(\func@var)%
\else#1\fi\func@def}
\newcommand\func@def[1][\@empty]{\ifx#1\@empty\relax\else%
\mathrel{:=}#1\fi\end{array}}
\makeatother
\begin{document}
Simple function: \[
\funcdef fx{\mathbf R}
\]
Simple function with declaration: \[
\funcdef fx{\mathbf R}*[x^2]
\]
Function with alternative writing: \[
\funcdef{\textrm{exp}}x{\mathbf R}[e^x]
\]textrm{exp}
Function with alternative writing and declaration: \[
\funcdef\exp x{\mathbf R}[e^x][\lim\limits_{n\to\infty}%
\left(1+\frac xn\right)^n]
\]
Function with different domain and codomain: \[
\funcdef{\textrm{sqrt}}n[\mathbf N]{\mathbf R}
\]
Function with different domain and codomain, and alternative
writing: \[
\funcdef{\textrm{sqrt}}n[\mathbf N]{\mathbf R}[\sqrt n]
\]
Function with different domain and codomain, alternative writing
and declaration: \[
\funcdef{\textrm{sqrt}}n[\mathbf N]{\mathbf R}[\sqrt n][\exp(\frac12\ln n)]
\]
\end{document}
有没有其他方法可以在 LaTeX2e 中定义这些类型的宏,而不需要太多的支持宏(此示例中为 5 个)和时间定义(此示例中为 2 个)?
它在 pain-TeX 或 LaTeX3 中如何工作?(这个问题的答案将被赞成但不会被接受)
答案1
我会使用完全不同的方法,使用键值语法。六个参数(其中一些是可选的)用*
表示缺少一个参数很容易出错。
\documentclass{article}
\usepackage{amsmath,keyval}
\makeatletter
\newcommand{\funcdef@key}[1]{%
\define@key{funcdef}{#1}{\@namedef{cet@#1}{##1}}%
\expandafter\let\csname cet@#1\endcsname\@empty
}
\funcdef@key{name}
\funcdef@key{domain}
\funcdef@key{codomain}
\funcdef@key{variable}
\funcdef@key{notation}
\funcdef@key{definition}
\newcommand{\funcdef@check}[1]{%
\expandafter\ifx\csname cet@#1\endcsname\@empty
\@latex@error{Missing `#1'}{Provide `#1'}%
\fi
}
\newcommand{\funcdef}[1]{%
\begingroup
\setkeys{funcdef}{#1}%
\ifx\cet@codomain\@empty\let\cet@codomain\cet@domain\fi
\funcdef@check{name}%
\funcdef@check{domain}%
\funcdef@check{variable}%
\begin{array}{l@{}r@{}l@{}l}
\cet@name\colon{} &
\cet@domain &
{}\to \cet@codomain \\
&
\cet@variable &
{}\mapsto
\ifx\cet@notation\@empty
\cet@name(\cet@variable)
\else
\cet@notation
\fi
\ifx\cet@definition\@empty
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{& {}\mathrel{:}=\cet@definition}
\\
\end{array}
\endgroup
}
\makeatletter
\begin{document}
\noindent
Simple function:
\[
\funcdef{name=f,variable=x,domain=\mathbf{R}}
\]
Simple function with declaration:
\[
\funcdef{
name=f,
variable=x,
domain=\mathbf{R},
notation=x^2
}
\]
Function with alternative writing:
\[
\funcdef{
name=\exp,
variable=x,
domain=\mathbf{R},
notation=e^x
}
\]
Function with alternative writing and declaration:
\[
\funcdef{
name=\exp,
variable=x,
domain=\mathbf{R},
notation=e^x,
definition=\lim\limits_{n\to\infty}\left(1+\frac xn\right)^n
}
\]
Function with different domain and codomain:
\[
\funcdef{
name=\operatorname{sqrt},
variable=n,
domain=\mathbf{N},
codomain=\mathbf{R}
}
\]
Function with different domain and codomain, and alternative
writing:
\[
\funcdef{
name=\operatorname{sqrt},
variable=n,
domain=\mathbf{N},
codomain=\mathbf{R},
definition=\sqrt{n}
}
\]
Function with different domain and codomain, alternative writing
and declaration:
\[
\funcdef{
name=\operatorname{sqrt},
variable=n,
domain=\mathbf{N},
codomain=\mathbf{R},
notation=\sqrt{n},
definition=\exp\bigl(\frac{1}{2}\ln n\bigr)
}
\]
\end{document}
这是 LaTeX3 中的实现,还有一个“内联”版本。
\documentclass{article}
\usepackage{amsmath,xparse}
\ExplSyntaxOn
\keys_define:nn { funcdef }
{
name .tl_set:N = \l_funcdef_name_tl,
name .initial:n = {},
domain .tl_set:N = \l_funcdef_domain_tl,
domain .initial:n = {},
codomain .tl_set:N = \l_funcdef_codomain_tl,
codomain .initial:n = {},
variable .tl_set:N = \l_funcdef_variable_tl,
variable .initial:n = {},
variables .tl_set:N = \l_funcdef_variables_tl,
variables .initial:n = {},
notation .tl_set:N = \l_funcdef_notation_tl,
notation .initial:n = {},
definition .tl_set:N = \l_funcdef_definition_tl,
definition .initial:n = {},
inline .bool_set:N = \l_funcdef_inline_bool,
}
\msg_new:nnnn { funcdef } { missing }
{
Missing~`#1'
}
{
You~have~to~specify~a~value~for~`#1';~%
I~have~substituted~??~for~it
}
\NewDocumentCommand{\funcdef}{ m }
{
\group_begin:
\funcdef_print:n { #1 }
\group_end:
}
\cs_new_protected:Npn \funcdef_print:n #1
{
\keys_set:nn { funcdef } { #1 }
\funcdef_check:n { name }
\funcdef_check:n { domain }
\tl_if_empty:NT \l_funcdef_variables_tl
{
\funcdef_check:n { variable }
}
\tl_if_empty:NT \l_funcdef_codomain_tl
{
\tl_set_eq:NN \l_funcdef_codomain_tl \l_funcdef_domain_tl
}
\bool_if:NTF \l_funcdef_inline_bool
{
\funcdef_print_inline:
}
{
\funcdef_print_array:
}
}
\cs_new_protected:Npn \funcdef_print_array:
{
\begin{array}{ l @{} r @{} l }
% first row
\l_funcdef_name_tl \colon {}
&
\l_funcdef_domain_tl
&
{}\to \l_funcdef_codomain_tl
\\
% second row
&
\tl_if_empty:NTF \l_funcdef_variable_tl
{
(\l_funcdef_variables_tl)
}
{
\l_funcdef_variable_tl
}
&
{}\mapsto
\tl_if_empty:NTF \l_funcdef_notation_tl
{
\l_funcdef_name_tl (
\tl_if_empty:NTF \l_funcdef_variable_tl
{
\l_funcdef_variables_tl
}
{
\l_funcdef_variable_tl
}
)
}
{
\l_funcdef_notation_tl
}
\tl_if_empty:NF \l_funcdef_definition_tl
{ \mathrel{:}= \l_funcdef_definition_tl }
\\
\end{array}
}
\cs_new:Npn \funcdef_print_inline:
{
\l_funcdef_name_tl \colon
\l_funcdef_domain_tl
\to \l_funcdef_codomain_tl
,\quad
\tl_if_empty:NTF \l_funcdef_variable_tl
{
(\l_funcdef_variables_tl)
}
{
\l_funcdef_variable_tl
}
\mapsto
\tl_if_empty:NTF \l_funcdef_notation_tl
{
\l_funcdef_name_tl (
\tl_if_empty:NTF \l_funcdef_variable_tl
{
\l_funcdef_variables_tl
}
{
\l_funcdef_variable_tl
}
)
}
{
\l_funcdef_notation_tl
}
\tl_if_empty:NF \l_funcdef_definition_tl
{ \mathrel{:}= \l_funcdef_definition_tl }
}
\cs_new_protected:Npn \funcdef_check:n #1
{
\tl_if_empty:cT { l_funcdef_#1_tl }
{
\msg_error:nnn { funcdef } { missing } { #1 }
\tl_set:cn { l_funcdef_#1_tl } { ?? }
}
}
\ExplSyntaxOff
\begin{document}
\noindent
Simple function inline:
\[
\funcdef{inline,name=f,variable=x,domain=\mathbf{R}}
\]
Simple function:
\[
\funcdef{name=f,variable=x,domain=\mathbf{R}}
\]
Simple function with declaration:
\[
\funcdef{
name=f,
variable=x,
domain=\mathbf{R},
definition=x^2
}
\]
Function with alternative writing:
\[
\funcdef{
name=\exp,
variable=x,
domain=\mathbf{R},
notation=e^x
}
\]
Function with alternative writing and declaration:
\[
\funcdef{
name=\exp,
variable=x,
domain=\mathbf{R},
notation=e^x,
definition=\lim\limits_{n\to\infty}\left(1+\frac xn\right)^n
}
\]
Function with different domain and codomain:
\[
\funcdef{
name=\operatorname{sqrt},
variable=n,
domain=\mathbf{N},
codomain=\mathbf{R}
}
\]
Function with different domain and codomain, and alternative
writing:
\[
\funcdef{
name=\operatorname{sqrt},
variable=n,
domain=\mathbf{N},
codomain=\mathbf{R},
definition=\sqrt{n}
}
\]
Function with different domain and codomain, alternative writing
and declaration:
\[
\funcdef{
name=\operatorname{sqrt},
variable=n,
domain=\mathbf{N},
codomain=\mathbf{R},
notation=\sqrt{n},
definition=\exp\bigl(\frac{1}{2}\ln n\bigr)
}
\]
Function of two variables:
\[
\funcdef{
name=f,
variables={a,b},
domain=A\times B,
codomain=C,
}
\]
\end{document}
答案2
使用 似乎很容易xparse
。唯一似乎很难做到的是强制使用您想要的确切语法来区分最后两个可选参数。使用下面的解决方案,以下内容是允许的(如您所愿):
\funcdef{f}{x}{R}
\funcdef{f}{x}{R}[2x]
\funcdef{f}{x}{R}[2x][x+x]
\funcdef{f}{x}{R}*[x+x]
但以下情况也是允许的:
\funcdef{f}{x}{R}[2x]*[x+x]
相当于第三个(前四个)。我不认为这有什么大问题;如果你觉得有什么问题,那修复起来就比较困难了。
\documentclass{article}
\usepackage{xparse}
\DeclareDocumentCommand{\funcdef}{m m o m o s o}{%
\begin{array}{r@{\ }c@{\,}c@{\,}l}
#1:
& \IfNoValueTF{#3}{#4}{#3}
& \to & #4 \\
& #2
& \mapsto
& \IfNoValueTF{#5}{#1(#2)}{#5}
\IfNoValueTF{#7}{}{\mathrel{:=}#7}
\end{array}
}
\begin{document}
Simple function: \[
\funcdef fx{\mathbf R}
\]
Simple function with declaration: \[
\funcdef fx{\mathbf R}*[x^2]
\]
Function with alternative writing: \[
\funcdef{\textrm{exp}}x{\mathbf R}[e^x]
\]
Function with alternative writing and declaration: \[
\funcdef\exp x{\mathbf R}[e^x][\lim\limits_{n\to\infty}%
\left(1+\frac xn\right)^n]
\]
Function with different domain and codomain: \[
\funcdef{\textrm{sqrt}}n[\mathbf N]{\mathbf R}
\]
Function with different domain and codomain, and alternative
writing: \[
\funcdef{\textrm{sqrt}}n[\mathbf N]{\mathbf R}[\sqrt n]
\]
Function with different domain and codomain, alternative writing
and declaration: \[
\funcdef{\textrm{sqrt}}n[\mathbf N]{\mathbf R}[\sqrt n][\exp(\frac12\ln n)]
\]
\end{document}