在Scheme / lisp中创建n个元素的列表?

时间:2018-01-31 00:00:52

标签: list recursion scheme lisp racket

我正在尝试创建n个元素的列表。它必须产生这个输出:

(my-list 5)
 >> 0 1 2 3 4

我有以下功能:

 (define (my-list n)
    (cond
          ((<= n 0) '())

    (else  (reverse-list   (cons (- n 1) 
                           (my-list(- n 1)))))
    )
 )

这就是生产

(my-list 10)
>>(8 6 4 2 0 1 3 5 7 9)

我理解这是因为在每次递归调用时都会反转列表,但我不确定这是正确的方法。我的反向清单工作正常。

提前致谢!

2 个答案:

答案 0 :(得分:3)

Scheme'build-and-reverse'中的一个标准习惯用法建议你只需要反转列表一次,最后,当反向完全构建时(从而将复杂度从二次方降低到O(N)。)

所以是的,你最终会对reverse进行尾调用,但是应该在没有这样做的情况下构建列表。 Scheme有很多本地递归绑定结构。

但是

如果你构建一个以最大值开头的范围(应该比列表的最后一个元素大一个),你最后不需要反转它,在每次迭代步骤中你减少一个计数器并在其前面添加已经积累的新价值:

(define (range n)
   (let rng ((m (- n 1)) (ret-val '())) ; named-let is very useful for small local recursive closures
      (if (< m 0)                       ; that original (<= n 0) check is also handled here
         ret-val                        ; here, the result is returned; note we don't need to reverse it
         (rng (- m 1) (cons m ret-val))))))

(display (range 10))
(newline)

打印

(0 1 2 3 4 5 6 7 8 9)

或者,为了演示构建和反向,我们可以从最低值开始:

(define (range-asc n)
   (let rng ((m 0) (ret-val '()))
      (if (= m n)
         (reverse ret-val) ; since we started from zero, we need to reverse it
         (rng (+ m 1) (cons m ret-val)))))

(看起来我还记得/可以恢复一些Scheme。: - O)

答案 1 :(得分:2)

首先,你的代码。格式正确它应该看起来像:

(define (my-list n)
    (cond ((<= n 0) '())
          (else (reverse-list (cons (- n 1) 
                                    (my-list (- n 1)))))))

您有问题,reverse-list致电。每次向列表中添加新元素时都会发生这种情况。您可以通过多种方式修复它,但简单的解决方案是将递归代码包装到本地函数中,并在返回时执行一些其他操作(在您的情况下反向)。

(define (my-list n)
    (define (build-list m)
        (cond ((<= m 0) '())
              (else (cons (- m 1)
                          (build-list (- m 1))))))
    (reverse-list (build-list n)))

因此,在my-list函数内,首先我们将递归部分定义为局部函数build-list。这正是您的代码,但删除了对reverse-list的调用。这部分将构建您的列表,但正如您所知,以相反的顺序。但这不再是一个问题,因为我们可以在本地函数返回时将其反转。