利弊什么时候会返回一个级联列表?

时间:2014-11-25 09:20:32

标签: scheme racket sicp r5rs

我正在进行SICP(计算机程序的结构和解释,第2版)2.18的练习,以制作一个程序来反转列表。这是我的代码:

(define (rev l)
  (if (null? (cdr l))
    l
    (cons (rev (cdr l)) (car l))))

当我使用(rev (list 1 2 3 4 5))对其进行测试时,它返回了:

(((((5) . 4) . 3) . 2) . 1)

这对我很奇怪。为什么它会返回一个级联列表?

我放的时候:

(cons 1
      (cons 2
            (cons 3 '())))

它返回(1 2 3)但不是(((1) 2) 3)


我正在使用语言R5RS在DrRacket中进行SICP练习。

我是否犯了错误或选择了错误的语言?

1 个答案:

答案 0 :(得分:1)

你需要了解一个列表是什么,与它相当亲密,成为一个好的lisper。 列表(1 2 3)只是(1 . (2 . (3 . ())))对的视觉糖,可以使用(cons 1 (cons 2 (cons 3 '())))

制作

结构(((((5) . 4) . 3) . 2) . 1)不是(5)以外的列表,(5 . ())(cons (cons (cons (cons (cons 5 '()) 4) 3) 2) 1)的视觉糖。可以使用(define (reverse lst) (define (reverse-aux lst acc) (if (null? lst) acc (reverse-aux (cdr lst) (cons (car lst) acc)))) (reverse-aux lst '()))

制作

制作清单时,您需要从头到尾制作清单。当您遍历列表时,您将从头到尾遍历它。要在处理时以与参数相同的顺序获取列表,您需要使用递归,以便当前步骤等待,直到尾部处理完成,直到最终结果为锥形,或者使用累加器处理列表完成后反转并反转结果。

您似乎正在尝试撤消列表,然后在迭代时只是累积列表:

let

如您所见,我定义了一个辅助函数来获取第三个参数,然后使用它。大多数Schemer更愿意在一个具有命名(define (reverse lst) (let reverse-aux ((lst lst) (acc '())) (if (null? lst) acc (reverse-aux (cdr lst) (cons (car lst) acc)))))

的操作中执行这两个操作
loop

这些完全一样。通常在进行迭代时,许多人使用名称reverse-aux代替((a b) c (d)),但它可以是任何名称,我选择保留第一个示例中的名称。

没有捷径。您需要能够查看(( a . (b ())) . (c . ((d . ()) . ())并考虑{{1}},因此您需要做很多练习。

在做SICP时,DrRacket使用哪种语言有look at my previous answer