我如何定义一个新命令,\natset[1]{#1}
使其给出如下输出?
(∅ = \varnothing);预期用途是数学模式例如$\natset[1]{#1}$
。牙套是人们通常会用到的东西$\{ \}$
。
生活在 TeX-ic 伪代码领域,我可能会这样做:
\newcommand{\natset}[1]{%
iter_set := \varnothing
\foreach \n in {1,...,#1}{%
temp_set := iter_set∪{iter_set}
iter_set := temp_set
\return iter_set}
- 我怎样才能将这样的循环转换成 LaTeX (以便进行编译
pdflatex
)?
我尝试过各种组合、、\newcommand
和\renewcommand
/\noexpand
或\expandafter
业务,但没有任何合理的结果。
基本前言和测试用例:
\documentclass[12pt]{article}
\usepackage{amsmath} %for \text inside $$ $$
\usepackage{amssymb} %for \varnothing
%\usepackage{xifthen} %maybe needed
\usepackage{tikz} %for-loop
%definition here
\makeatletter
\newcommand{\natset}[1]{#1}
\makeatother
\begin{document}
$$\text{0 gives}\qquad \natset{0}$$
$$\text{1 gives}\qquad \natset{1}$$
$$\text{2 gives}\qquad \natset{2}$$
$$\text{8 gives}\qquad \natset{8}$$
\end{document}
我以后还有关于这个命令的其他计划(比如添加可选参数、将样式更改为 Zermelo 的自然数等)。冯·诺依曼的东西希望能让我入门。当然,任何复杂的答案都是受欢迎的,但更简单的答案(从句法上来说)可能最有帮助。或者带有一些额外评论的复杂答案。
答案1
我认为使用递归比循环更自然,例如
\documentclass{article}
\usepackage{amssymb}
\newcommand\nnatset[1]{%
\ifnum#1=0 \varnothing \else
\ifnum#1>1 \nnatset{\numexpr#1-1},\{\fi\nnatset{\numexpr#1-1}\ifnum#1>1 \}\fi
\fi}
\newcommand\natset[1]{\ifnum#1>0\{\fi\nnatset{#1} \ifnum#1>0\}\fi}
\begin{document}
$\natset{0}$
$\natset{1}$
$\natset{2}$
$\natset{3}$
\end{document}
答案2
这个解决方案的有趣之处在于,我实际上将其构建为空组的 TeX 组(即根据放置在宏中的实际冯·诺依曼分组\z
)。然后我使用tokcycle
以可排版的方式解释 catcode-1,2 组。
\documentclass{article}
\usepackage{tokcycle,amssymb}
\newcommand{\natset}[1]{\def\z{}\natsetaux{#1}}
\newcommand\natsetaux[1]{%
\ifnum\numexpr#1\relax>0\relax
\edef\z{\z{\z}}%
\natsetaux{#1-1}%
\else
\expandedtokcyclexpress{{\z}}%
\fi}
\Groupdirective{%
\if\relax#1\relax\varnothing\else
\ifnum\tcdepth>1\relax,\fi\{\processtoks{#1}\}\fi}
\begin{document}
$\natset 0$
$\natset 1$
$\natset 2$
$\natset 3$
$\natset 4$
\end{document}
为了更好地理解,对于\natset 3
, 的值是d 模式\z
中的 catcode 1 和 2 个括号(不可排版)\detokenize
然后,每次在输入流中遇到括号组时,tokcycle
都会将扩展的输入输入到其中{\z}
并执行。在里面,术语指的是组的内容。如果它是一个空组,我会排版。否则,我会根据需要放置一个逗号,并将非空组内容重新提交给标记循环,同时将排版括号放在结果周围。生成的排版给出\Groupdirective
\Groupdirective
#1
\varnothing
最后,我只想补充一点,上面的实现\natsetaux
是为了便于理解而编写的。但是,它在递归过程中使用了堆栈,因为\fi
s 会不断积累,并且只有在最终完成时才会释放。对于 的小参数来说,这不是问题\natset
。但是,如果要将其用于大量扩展,最好以\natsetaux
一种在下一次递归调用之前完成自身的方式重新实现。以下是这样的一种方法:
\newcommand\natsetaux[1]{\tctestifnum{#1>0}{\edef\z{\z{\z}}%
\expandafter\natsetaux\expandafter{\the\numexpr#1-1}}
{\expandedtokcyclexpress{{\z}}}}
答案3
粗制 LaTeX3 溶液:
\documentclass{article}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{expl3}
\usepackage{xparse}
\ExplSyntaxOn
\int_new:N \l_natset_tmpa_int
\NewDocumentCommand \natset { m }
{
\int_set:Nn \l_natset_tmpa_int { #1 }
\int_compare:nNnTF { \l_natset_tmpa_int } = { 0 }
{
\varnothing
}
{
\{ \varnothing
\int_step_inline:nnn { 1 } { \l_natset_tmpa_int - 1 }
{
, \natset { ##1 }
}
\}
}
}
\ExplSyntaxOff
\begin{document}
\begin{align*}
0 &= \natset{0} \\
1 &= \natset{1} \\
2 &= \natset{2} \\
3 &= \natset{3} \\
4 &= \natset{4} \\
5 &= \natset{5}
\end{align*}
\end{document}