非尾递归和参数扩展顺序

非尾递归和参数扩展顺序

我无法理解 TeX 宏的扩展顺序:

\newcount\x

\def\dec#1{%
  \ifnum#1=0
    .%
  \else
    #1%
    \x=#1
    \advance\x by-1
    \dec{\number\x}%
    #1%
  \fi%
}
\dec{5}

\bye

上面的非尾递归结果是54321.00005,而不是。我明白我想要的可以通过在递归扩展后54321.12345恢复来实现。但是,我不太明白为什么这会导致。\x\dec00005

有人能告诉我吗?谢谢。

答案1

\newcount\x

\def\dec#1{%
  \ifnum#1=0
    .%
  \else
    #1%
    \x=#1
    \advance\x by-1
    \dec{\number\x}%
    #1%
  \fi%
}

{\tracingmacros1 \tracingonline1
\dec{5}
}
\bye

生产

\dec #1->\ifnum #1=0 .\else #1\x =#1 \advance \x by-1 \dec {\number \x }#1\fi 
#1<-5

\dec #1->\ifnum #1=0 .\else #1\x =#1 \advance \x by-1 \dec {\number \x }#1\fi 
#1<-\number \x 

\dec #1->\ifnum #1=0 .\else #1\x =#1 \advance \x by-1 \dec {\number \x }#1\fi 
#1<-\number \x 

\dec #1->\ifnum #1=0 .\else #1\x =#1 \advance \x by-1 \dec {\number \x }#1\fi 
#1<-\number \x 

\dec #1->\ifnum #1=0 .\else #1\x =#1 \advance \x by-1 \dec {\number \x }#1\fi 
#1<-\number \x 

\dec #1->\ifnum #1=0 .\else #1\x =#1 \advance \x by-1 \dec {\number \x }#1\fi 
#1<-\number \x 

所以你会看到你每次都没有传递不同的值,每个参数都是\number \x如此,最后你有多个,\number\x 所以它们都打印 0


你可以\number在递归之前进行扩展

\newcount\x

\def\dec#1{%
  \ifnum#1=0
    .%
  \else
    #1%
    \x=#1
    \advance\x by-1
    \expandafter\dec\expandafter{\number\x}%
    #1%
  \fi%
}

{\tracingmacros1 \tracingonline1
\dec{5}
}
\bye

生产

\dec #1->\ifnum #1=0 .\else #1\x =#1 \advance \x by-1 \expandafter \dec \expand
after {\number \x }#1\fi 
#1<-5

\dec #1->\ifnum #1=0 .\else #1\x =#1 \advance \x by-1 \expandafter \dec \expand
after {\number \x }#1\fi 
#1<-4

\dec #1->\ifnum #1=0 .\else #1\x =#1 \advance \x by-1 \expandafter \dec \expand
after {\number \x }#1\fi 
#1<-3

\dec #1->\ifnum #1=0 .\else #1\x =#1 \advance \x by-1 \expandafter \dec \expand
after {\number \x }#1\fi 
#1<-2

\dec #1->\ifnum #1=0 .\else #1\x =#1 \advance \x by-1 \expandafter \dec \expand
after {\number \x }#1\fi 
#1<-1

\dec #1->\ifnum #1=0 .\else #1\x =#1 \advance \x by-1 \expandafter \dec \expand
after {\number \x }#1\fi 
#1<-0

在此处输入图片描述


使用 etex (包括 pdftex、luatex、xetex 等) 您不需要\x


\def\dec#1{%
  \ifnum#1=0
    .%
  \else
    #1%
    \expandafter\dec\expandafter{\number\numexpr#1-1\relax}%
    #1%
  \fi%
}

{\tracingmacros1 \tracingonline1
\dec{5}
}
\bye

答案2

通过 TeX的 -branch#1中的最后一个,内存中会累积 token,而不是求值的结果(每次迭代都会产生另一个结果)。当最后一次迭代后对所有累积进行求值时,的值为0。\else\dec\number\x\number\x\number\x\x

为了更清楚地了解正在发生的事情,让我们通过\expandafterand \numberbefore 来评估参数\exchange,并将评估结果放在分支的末尾\else/关闭之前\fi

\newcount\x

\long\def\exchange#1#2{#2#1}

\def\dec#1{%
  \ifnum#1=0
    .%
  \else
    #1%
    \expandafter\exchange\expandafter{\number#1}{%
      \x=#1
      \advance\x by-1
      \dec{\number\x}%
    }%
  \fi%
}
\dec{5}

\bye

此代码仅用于展示问题代码存在什么问题。

对于实际用途来说,David Carlisle 在他的回答中提供的代码要好得多。

相关内容