将宏的扩展版本以纯格式存储到另一个宏中

将宏的扩展版本以纯格式存储到另一个宏中

我编写了以下宏,打印出用逗号分隔的一系列数字:

\newcount\tmpnum

\def\range#1#2#3{\tmpnum=#2
    \loop\the\tmpnum\advance\tmpnum by #1
        \ifnum\tmpnum<#3,\repeat,
}

例如,\range{2}{3}{10}扩展为3,5,7,9,

我想将此扩展存储到宏中\therange。我尝试的是:

\edef\therange{\range{2}{3}{10}}
% Should be the same as
% \def\therange{3,5,7,9,}

但我收到错误消息。为什么?如何实现我的目标?

答案1

\def\range#1#2#3{\altrange{#2}{#3}{#1}}
\def\altrange#1#2#3{\ifnum #1<\numexpr 1+#2\relax#1,\expandafter
  \altrange\expandafter{\the\numexpr#1+#3\relax}{#2}{#3}\fi}

\edef\therange{\range{2}{3}{10}}

\edef\z{\range{3}{3}{15}}

The range is \therange\ while z is \z

\bye

在此处输入图片描述

如果有人想争论我是否用未解决的\fis 构建堆栈,直到最后(这只能成为非常大的列表的一个因素),那么人们可以玩“自由-\fi我从 David 那里学到的“Free- -Fo'-Fun”游戏(尝试消除递归过程中的堆栈溢出(字母冒泡排序器)):

\def\range#1#2#3{\ifx11\altrange{#2}{#3}{#1}\fi}
\def\altrange#1#2#3\fi{\fi\ifnum #1<\numexpr 1+#2\relax#1,\expandafter
  \altrange\expandafter{\the\numexpr#1+#3\relax}{#2}#3\fi}

\edef\therange{\range{2}{3}{10}}

\edef\z{\range{3}{3}{15}}

The range is \therange\ while z is \z

\bye

答案2

其他答案已经展示了如何做到这一点,我想解释一下你的方法为什么会失败。

只有一些 TeX 基元纯粹通过扩展工作 - 也就是说它们可以在 或类似 内实现其结果\edef\message特别是,没有什么

  • 执行任务
  • 有排版吗

通过扩展来实现。在普通 TeX 中的定义\loop使用赋值,因此不能在这样的上下文中使用。有几种方法可以设置没有赋值的循环,如其他答案所示。

我注意到你正在使用 LuaTeX:重要的是要注意 Lua 级别的分配允许,因此如果你用 Lua 编写代码,‘规则会有所不同’。

答案3

\edef命令不执行分配并且您的循环充满了分配。

有了luatex您就可以使用expl3

\input expl3-generic

\ExplSyntaxOn

\cs_new:Npn \range #1 #2 #3
 {% #1 is the step, #2 the starting point, #3 the upper bound
  #2
  \int_step_function:nnnN { #2 + #1 } { #1 } { #3 } \user_addtorange:n
 }
\cs_new:Nn \user_addtorange:n { , #1 }

\ExplSyntaxOff

\range{2}{3}{10}

\edef\therange{\range{2}{3}{10}}

{\tt\meaning\therange}

\bye

在此处输入图片描述

该函数\int_step_function:nnnN的语法如下

\int_step_function:nnnN { <start> } { <step> } { <end> } <function>

应该<function>是一个单参数函数(宏,用普通的 TeX 术语来说),它将以显而易见的方式传递通过循环得到的所有整数。只<end>传递不超过的整数。该函数将扩展为,<current integer>。开头是预先添加的,因此我们不会遇到虚假逗号的问题。

没有的版本expl3,只是为了好玩。

\def\range#1#2#3{% #1 = step, #2 = start, #3 = upper bound
  \betterrange{#2}{#3}{#1}%
}
\def\betterrange#1#2#3{% #1 = start, #2 = upper bound, #3 = step
  #1%
  \ifnum\numexpr#1+#3>\numexpr#2\relax
    \expandafter\gobble
  \else
    \expandafter\firstofone
  \fi
  {\expandafter,\expandafter\betterrange\expandafter{\the\numexpr#1+#3}{#2}{#3}}%
}
\def\gobble#1{}
\def\firstofone#1{#1}

\range{2}{3}{10}

\edef\therange{\range{2}{3}{10000}}

\show\therange

\bye

答案4

这是可扩展循环的典型问题。这里展示了各种解决方案。我展示了另一种使用\fornumstepOpTeX 可扩展的解决方案(luaTeX + 增强型纯 TeX):

\def\range#1#2#3{\fornumstep #1: #2..#3 \do{##1,}}
%test:
\edef\therange{\range{2}{3}{10}}
\meaning\therange
\bye

相关内容