【发布时间】:2020-12-28 19:33:05
【问题描述】:
我的问题是:如何编写一个利用尾调用的过程,并且构造一个不按相反顺序的列表。 为了说明我的意思,下面是一个非常简单的迭代过程示例,它创建了一个列表的副本:
(define (copy-list ls)
(define (iter cp-ls rest-ls)
(if (null? rest-ls)
cp-ls
(iter (cons (car rest-ls) cp-ls) (cdr rest-ls))))
(iter '() ls))
问题在于,由于元素consed 在一起的迭代顺序,返回的列表最终被颠倒了。是的,您可以通过在if 块中执行(reverse cp-list) 而不仅仅是cp-list 来轻松解决此问题,但问题在于reverse 是一个递归过程。使用此过程将抵消尾调用的优势,即堆栈大小随输入大小线性增长。
那么,基本上,如何编写像上面提到的那样以正确顺序返回列表的过程不使用任何类型的递归过程?
谢谢
【问题讨论】:
-
将
(iter '() ls)更改为(iter '() (iter '() ls))是否可行? -
@RowPJ 我不在乎别人怎么说,但这实际上是一种天才。谢谢
-
我不认为
reverse是作为递归过程实现的,实际上我认为它的实现与您的iter过程几乎完全一样。所以你的程序基本上是在做(reverse (reverse ls))。如果你不改变列表,实际上没有必要“复制”它们,它在你的程序中没有任何有用的效果。 -
@WillNess 是的,tailcall 意味着 恒定 堆栈增长。我实际上知道这一点,而我写的确实是脑放屁。感谢您的澄清。一个问题:无论堆栈在哪里,迭代和线性过程的增长率仍然存在?那么,当你说 Racket 中的迭代和递归没有区别时,这究竟是什么意思呢?我的意思是,在递归过程中,每次对内存的递归调用都是解析最终返回值所必需的,而迭代过程并非如此。
标签: list functional-programming scheme lisp tail-call-optimization