我想实现范围函数(start,end,inc),它从头到尾生成所有自然数,并增加inc。 这是第一个版本:
(define (gen start end step)
(if (>= start end)
'()
(cons start (gen (+ step start) end step))))
问题是,这不是尾递归。另一个尝试:
(define (gen-iter start end step acc)
(if (>= start end)
acc
(gen-iter (+ step start) end step (cons start acc))))
但这会以相反的顺序生成一个列表:) 所以,是的,我可以用O(n)来反转它,并且很高兴,但我有点卡在这里,试图创建一个函数,从头到尾构建一个具有正确顺序的列表,不附加每次迭代< / strong>,因为附加费用很高。 还有一个内置列表,但我不知道它是如何运作的。
答案 0 :(得分:4)
正如uselpa在评论中已经说过,解决方案是在最后使用dynamic_cast<>
。扩展后,static_cast<>
的球拍实施与reverse
range
功能的结果非常相似,除了您可能没有想到的某些情况。
球拍中reverse
的实际实施使用gen-iter
,但扩展到的实际上等同于
range
除了使用(for/list ([i (in-range start end step)]) i)
函数而不是(reverse
(for/fold ([fold-var null])
([i (in-range start end step)])
(cons i fold-var)))
之外,它使用alt-reverse
来更好地报告错误。如果你扩展它,它在经过一些简化(删除不必要的reverse
包装,错误检查等)之后就相当于这个。)
for/fold/derived
命名为let,相当于定义一个这样的辅助函数:(在替换一些let-values
并将助手提升到(reverse
(let ([start start] [end end] [inc step])
(let for-loop ([fold-var null] [pos start])
(if (if (>= step 0)
(< pos end)
(> pos end))
(let ([i pos])
(let ([fold-var (cons i fold-var)])
(for-loop
fold-var
(+ pos inc))))
fold-var))))
函数之外)之后
let
这仍然与您的解决方案不同,因为您的解决方案假定range
为正,而即使(define (range start end step)
(reverse
(range-reversed null start end step)))
(define (range-reversed fold-var pos end step)
(if (if (>= step 0)
(< pos end)
(> pos end))
(range-reversed
(cons pos fold-var)
(+ pos step)
end
step)
fold-var))
为负,此解决方案仍然有效。如果step
为正数,则if条件为step
而不是嵌套if。
它还使用step
您使用的(< pos end)
,但它也会切换if个案。如果(< pos end)
与(>= pos end)
相同,则与您的解决方案相同,因为(< x y)
等同于(not (>= x y))
。但是,至少有一个案例,我可以想到哪些情况不成立,(if (not a) b c)
或(if a c b)
为start
。对于这种情况,球拍的end
函数将返回一个空列表,而您的解决方案将进入无限循环。
答案 1 :(得分:3)
它并不总是那么容易看到它,但是反过来&#34;这是一个关键字。为了使它迭代,你需要反过来做实际的工作:
(define (my-range start end step)
(define (helper n acc)
(if (= end n)
(cons n acc)
(helper (- n step) (cons n acc))))
(define actual-end end) ; this needs improvement
(helper actual-end '()))
就像球拍中的range
一样,你应该得到以下结果:
(my-range 1 10 1) ; ==> (1 2 3 4 5 6 7 8 9)
(my-range 10 1 -1) ; ==> (10 9 8 7 6 5 4 3 2)
要获得正确的actual-end
需要,请根据数学找到正确的值。
(my-range 1 10 2) ; ==> (1 3 5 7 9) (actual-end should be 9)
(my-range 10 1 -2) ; ==> (10 8 6 4 2) (actual-end should be 2)
我猜你可以使用ceiling
程序和正常的数学程序来确保这一点。