【问题标题】:Creating a list of n elements in Scheme/lisp?在Scheme / lisp中创建n个元素的列表?
【发布时间】:2018-07-09 23:41:18
【问题描述】:

我正在尝试创建一个包含 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)

我知道这是由于在每次递归调用时都会反转列表,但我不确定什么是正确的方法。我的反向列表也工作正常。

提前致谢!

【问题讨论】:

  • 如果我调用函数并输入一个列表,它是正确的反转
  • @Kattie.S 你的代码不可读,可以重新格式化吗?
  • 现在好点了吗?

标签: list recursion scheme lisp racket


【解决方案1】:

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)

【讨论】:

  • 谢谢!我还想知道是否有一种方法可以完全使用递归构建列表,然后使用 reverse-list 辅助函数对其进行反转?
  • 在玩弄了这段代码之后,它似乎没有在 "(rng (- m 1) (cons m ret-val))" 处运行,因为它不解释 (rng. .. 作为一个函数。
  • Report 的哪个版本以及您使用的是什么实现?早在 R5RS 中就已经描述了命名 let,并且可能早在此之前:schemers.org/Documents/Standards/R5RS/HTML/…
【解决方案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 的调用。这部分将建立您的列表,但如您所知,顺序相反。但这不再是问题,因为我们可以在本地函数返回时反转它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-07
    • 2018-06-18
    • 1970-01-01
    • 2018-05-24
    • 1970-01-01
    • 1970-01-01
    • 2010-11-10
    相关资源
    最近更新 更多