我使用local-time
编写了以下循环:
(defun count-dates (stop-date k)
(loop for step = (local-time:today)
then (local-time:timestamp- step 1 :day)
while (local-time:timestamp>= step stop-date)
collect (funcall k step)))
它可以像这样运行:
(count-dates (local-time:encode-timestamp 0 0 0 0 1 1 2019) #'princ)
虽然这很简单明了,但我想知道如何在不使用全能
loop
结构的情况下编写它,并提出:(defun count-dates2 (stop-date k)
(reverse (labels ((f (acc step)
(if (local-time:timestamp>= step stop-date)
(f (cons (funcall k step) acc)
(local-time:timestamp- step 1 :day))
acc)))
(f '() (local-time:today)))))
这似乎过于复杂,使用
reverse
和累加器有没有一种更简单的方法来实现与循环相同的效果,而不必进行变异,也不可能溢出堆栈? 最佳答案
不在常见的Lisp中,不:如果您想要一个迭代构造,您需要使用显式迭代构造:CL不保证语法递归构造实际上是迭代的loop
不是唯一的迭代构造,当然您可以编写自己的迭代和结果集合构造。
实际上,并不能保证您的第二个版本不会在cl中溢出堆栈:大多数当前实现将尾调用编译为迭代,尽管在解释的代码中可能无法处理,但有些实现受其目标(例如jvm)的约束而不能这样做。也有一些主要的历史原生代码实现没有(例如符号CL)。
有一些Lisp族语言确实在语言中指定尾部调用是迭代的,特别是Scheme,在这种语言中,第二个版本就可以了。
至于需要向后建立列表然后反转它们的问题:我认为这是LISPS中列表方式的必然结果:如果你不乐意改变现有的列表或者每一步都采取批量复制的方式,那么你只需要增加列表来增加列表。
当然,你可以隐藏你在幕后构建的列表的变异,这样你就永远不需要知道发生了什么,但这并不意味着它既不会变异结构,也不会反向构建结构,然后反向构建例如,我有一个结构,它看起来像:
(collecting
...
(collect ...)
...)
它向前构建列表,但它通过保持尾部指针并改变正在构建的列表来实现。