【问题标题】:Help explaining how `cons` in Scheme work?帮助解释 Scheme 中的 `cons` 是如何工作的?
【发布时间】:2011-04-21 07:49:20
【问题描述】:

这是删除列表最后一个元素的函数。

(define (remove-last ll)
  (if (null? (cdr ll))
      '()
      (cons (car ll) (remove-last (cdr ll)))))

所以根据我的理解,如果我们cons 一个列表(例如a b c 带有一个空列表,即'(),我们应该得到 a b c。但是,在交互窗口(DrScheme)中测试,结果是:

如果 (cons '() '(a b c))

(() a b c)

如果 (cons '(a b c) '())

((a b c))

我很喜欢 :(! 然后我回到我的问题,删除所有相邻重复的元素。例如, (a b a a c c) 将是 (a b)

(define (remove-dup lst)
  (cond ((null? lst) '())
        ((null? (cdr lst)) (car lst))
        ((equal? (car lst) (car (cdr lst))) (remove-dup (cdr (cdr lst))))
        (else (cons (car lst) (car (cdr lst))))
        )

  )

这是不正确的,但是我意识到答案在a b 之间有一个.。怎么会这样?

`(a . b)`

在我上面的代码中只有一个对cons 的调用,我看不出哪个部分可以生成这个.。有什么想法吗?

谢谢,

【问题讨论】:

    标签: scheme


    【解决方案1】:

    cons 构建对,而不是列表。 Lisp 解释器使用“点”在视觉上分离对中的元素。所以(cons 1 2) 将打印(1 . 2)carcdr 分别返回一对的第一个和第二个元素。列表建立在对之上。如果一对中的cdr 指向另一对,则该序列被视为一个列表。最后一对的cdr 将指向一个名为null(由'() 表示)的特殊对象,这告诉解释器它已到达列表的末尾。例如,列表'(a b c) 是通过计算以下表达式来构造的:

    > (cons 'a (cons 'b (cons 'c '())))
    (a b c)
    

    list 过程提供了创建列表的快捷方式:

    > (list 'a 'b 'c)
    (a b c)
    

    表达式(cons '(a b c) '()) 创建一个第一个元素是一个列表的对

    您的remove-dup 过程正在else 子句处创建一对。相反,它应该通过递归调用remove-dup 并将结果作为该对的第二个元素来创建一个列表。我已经清理了一些程序:

    (define (remove-dup lst)
      (if (>= (length lst) 2)
          (if (eq? (car lst) (cadr lst))
              (cons (car lst) (remove-dup (cddr lst)))
              (cons (car lst) (remove-dup (cdr lst))))
          lst))
    

    测试:

    > (remove-dup '(a b c))
    (a b c)
    > (remove-dup '(a a b c))
    (a b c)
    > (remove-dup '(a a b b c c))
    (a b c)
    

    另请参阅SICP 中的第 2.2 节(分层数据和闭包属性)。

    为了完整起见,这里是remove-dup 的一个版本,它删除了所有相同的相邻元素:

    (define (remove-dup lst)
      (if (>= (length lst) 2)
          (let loop ((f (car lst)) (r (cdr lst)))
            (cond ((and (not (null? r))(eq? f (car r)))
                   (loop f (cdr r)))               
                  (else
                   (cons (car lst) (remove-dup r)))))
          lst))
    

    【讨论】:

      【解决方案2】:

      这里是伪代码:

      类对{ 对象离开, 对象右}。

      function cons(Object left, Object right) {return new Pair(left, right)};

      所以, 1. 缺点('A,'B) => 对('A,'B) 2. cons('A,NIL) => Pair('A,NIL) 3. 缺点(NIL,'A) => 对(NIL,'A) 4. cons('A,cons('B,NIL)) => Pair('A, Pair('B,NIL)) 5. cons(cons('A 'B),NIL)) => Pair(Pair('A,'B),NIL)

      让我们看看所有情况下的左右: 1. 'A 和 'B 是原子,整个 Pair 不是列表,所以 (const 'a 'b) 在 scheme 中给出 (a . b) 2. NIL 是一个空列表,'A 是一个原子,(cons 'a '()) 给出列表 (a) 3. NIL 和 'A 同上,但左边是 list(!), (cons '() 'a) 给出对 (() .a) 4. 简单的情况,我们在这里有适当的列表(a b)。 5. 正确的列表,head 是 pair (a . b),tail 是空的。

      希望你明白了。

      关于你的功能。您在 LIST 上工作但构建 PAIRS。 列表是对(对),但并非所有对都是列表!要成为列表对必须有 NIL 作为尾部。

      (a b) 对&列表 (a . b) 对未列出

      尽管有缺点,但您的函数有错误,它只是在 '(a b a a c c d) 上不起作用。由于这与您的问题无关,因此我不会在此处发布解决方法。

      【讨论】:

        猜你喜欢
        • 2011-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-23
        • 2018-09-13
        相关资源
        最近更新 更多