制作范围宏

制作范围宏

在编程语言中,使用范围的语法糖很有用。例如,在 Ruby 中,可以使用以下方式使用范围:

(2..10).map {|elem| elem + 1}

获取由范围内每个元素加一组成的数组([3, 4, ..., 11])。

我发现看一下使用 Alonzo Church 的 lambda 逻辑的其他语言中事情是如何完成的很有帮助,在本例中是 Scheme:

(define (range low high)
  (cond
    [(> low high) null]
    [else (cons low (range (+ low 1) high))]))

(我假设[...]-syntax 特定于 PLT Scheme。以上内容取自此网页

那么,递归,是吗?当然,为什么不呢:

\def\range#1#2{\ifnum#1>#2\else#1, \range{\the\numexpr#1+1\relax}{#2}\fi}
\range{2}{10}
\bye

好吧,我得到了范围(末尾有一个多余的逗号),但它开始对更大的范围感到困惑。为什么?查看日志文件可能会给出一些线索\tracingmacros=2

\range #1#2-><macro definition>
#1<-\the \numexpr \the \numexpr \the \numexpr \the \numexpr ...
#2<-10

好的,我明白了。

所以我需要加入一些\expandafters,对吗?:

\catcode`@=11

\def\R@nge#1#2{\number#1 \ifnum#1<#2, \expandafter\R@nge
    \expandafter{\number\numexpr#1+1\expandafter}%
    \expandafter{\number#2\expandafter}\fi}

\R@nge{2}{10}
\bye

现在它不呛水了。

我爱上了 Alan Jeffreylambda.sty在 TeX 口中的列表,因此我的本能是尝试将该范围制作成一个列表:

\catcode`@=11
\input lambda.sty
\def\R@nge#1#2{\number#1 \ifnum#1<#2, \expandafter\R@nge
    \expandafter{\number\numexpr#1+1\expandafter}%
    \expandafter{\number#2\expandafter}\fi}

\Unlistize{\Listize[\R@nge{2}{10}]} % works, but getting back to the ruby example,

\def\Succ#1{\the\numexpr#1+1\relax}

\Unlistize{\Map\Succ{\Listize[\R@nge{2}{10}]}} % doesn't work
% (expected result: [3, 4, 5, 6, 7, 8, 9, 10, 11],
% instead of: [2, 3, 4, 5, 6, 7, 8, 9, 10+1].)
\bye

也许这些\expandafters 到了这个阶段又开始困扰我了?

因此接下来我尝试更严格地遵循 Scheme 版本:

\catcode`@=11
\input lambda.sty
\def\Range#1#2{\TeXif{\ifnum#1>#2}{\Nil}%
  {\Cons{#1}{\Range{\number\numexpr#1+1}{#2}}}}

\Unlistize{\Range{2}{10}}
\bye

看起来和 Scheme 版本差不多,不是吗?唉,它返回一个空列表!

问题

我如何制作一个范围宏来输出一个列表(在意义上lambda.sty)以便我可以使用\Map等等?

我隐约觉得该命令应该类似于\Listize-macro lambda.sty

\def\Listize[#1]%
   {\Listize@#1,\relax]}
\def\Listize@#1,#2]%
   {\TeXif{\ifx\relax#2}%
        {\Singleton{#1}}%
        {\Cons{#1}{\Listize@#2]}}}

但我还不知道该改变什么以及如何改变。

答案1

当心(不要)终止数字!

\catcode`@=11
\input lambda.sty
\def\Range[#1..#2]{\TeXif{\ifnum#1>#2 }{\Nil}%
  {\Cons{#1}{\expandafter\Range\expandafter[\number\numexpr#1+1\relax..#2]}}}

\immediate\write20{\Unlistize{\Range[2..10]}}


\bye

我在后面添加了一个空格#2,并\relax在后面添加了一个\numexpr

$ pdftex ltest2
This is pdfTeX, Version 3.1415926-2.3-1.40.12 (TeX Live 2011/Cygwin)
 restricted \write18 enabled.
entering extended mode
(./ltest2.tex (./lambda.sty)
[2, 3, 4, 5, 6, 7, 8, 9, 10]
 )
No pages of output.
Transcript written on ltest2.log.

相关内容