在编程语言中,使用范围的语法糖很有用。例如,在 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
好的,我明白了。
所以我需要加入一些\expandafter
s,对吗?:
\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
也许这些\expandafter
s 到了这个阶段又开始困扰我了?
因此接下来我尝试更严格地遵循 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.