在计划中反转列表

时间:2016-07-13 17:23:21

标签: recursion scheme reverse sicp mit-scheme

我正在尝试撤销计划中的列表,我想出了以下解决方案:

(define l (list 1 2 3 4))

(define (reverse lista)
    (car (cons (reverse (cdr (cons 0 lista))) 0)))

(display (reverse l))

虽然它有效但我真的不明白为什么会有效。

在我的脑海里,它将评估一系列嵌套的缺点,直到()(带有一个元素的列表的cdr)的cons(。)

我想我不理解替代模型,有人可以解释一下它的工作原理吗?

Obs:

  • 它应该只在非嵌套列表中起作用。

  • 采取SICP形式,练习2.18。

  • 我知道有很多类似的问题,但据我所见,没有人提出过 这个解决方案。

谢谢

3 个答案:

答案 0 :(得分:1)

这与其他语言的解决方案几乎完全相同:

  • 如果列表为空,则返回一个空列表。否则......
  • 砍掉第一个元素(CAR)
  • 反转列表的其余部分(CDR)
  • 追加(CONS)该逆转的第一个元素
  • 返回结果

现在......根据我对LISP日的理解,代码看起来更像是这样:

(append (reverse (cdr lista)) (list (car lista)))

...符合我上面的描述。

答案 1 :(得分:1)

[因为这种情况经常发生,我总是写下答案]

Scheme实现确实有内置版本的reverse,map,append等,因为它们在RxRS中指定(例如https://www.cs.indiana.edu/scheme-repository/R4RS/r4rs_8.html)。

在学习计划(实际上是任何lisp方言)的过程中,无论如何实施它们确实很有价值。危险的是,一个人的定义可能与内置的一个碰撞(尽管例如方案的定义或者lisp的标签应该遮蔽它们)。因此,总是值得用其他名称来称呼这个手工制作的实现,比如“my-reverse”,“my-append”等。这样你就可以省去很多困惑,如下所示:

(let ([append
        (lambda (xs ys)
          (if (null? xs)
              ys
              (cons (car xs) (append (cdr xs) ys))))])
 (append '(hello) '(there!)))

- 这个似乎可以正常工作,创建一个错误的印象,“let”的工作方式与“letrec”相同。但只是将名称更改为“my-append”并且它会中断,因为在评估lambda表单时,符号“my-append”尚未绑定到任何内容(不像“append”,它被定义为内置过程) )。

当然这样的表单将使用动态作用域的语言,但是scheme是词法(除了“define”s),原因是引用透明度(但是到目前为止,我只能引用感兴趣的offtopic)读者阅读其中一篇lambda论文http://repository.readscheme.org/ftp/papers/ai-lab-pubs/AIM-453.pdf)。

答案 2 :(得分:0)

有几种方法可以做到这一点。这是另一个:

(define my-reverse
  (lambda (lst)
    (define helper
      (lambda (lst result)
        (if (null? lst)
            result
            (helper (cdr lst) (cons (car lst) result)))))
    (helper lst '())))