我想了解每行代码如何删除列表中的重复项,因此这是列表(a b a a c c)给出(a b)

时间:2017-04-07 05:29:48

标签: scheme lisp

这是代码及其在方案lisp

上的正常工作
(define (rdup ls)
  (let loop ((ls ls) (current #f))
    (cond ((null? ls)               ())
          ((null? (cdr ls))         (if (eq? (car ls) current) () ls))
          ((eq? (car ls) (cadr ls)) (loop (cdr ls) (car ls)))
          ((eq? (car ls) current)   (loop (cdr ls) current))
          (else                     (cons (car ls) (loop (cdr ls) (car ls)))) )))

这是我试过的

(rdup '(a b a a a c c))

得到(a b)

我想知道代码的每一行是如何工作的

1 个答案:

答案 0 :(得分:0)

我添加了行号并修复了缩进以便于解释:

01 (define (rdup ls)
02 (let loop ((ls ls)
03 (current #f))  
04  (cond
05   ((null? ls) '())
06   ((null? (cdr ls)) 
07        (if (eq? (car ls) current) '() ls))
08   ((eq? (car ls) (cadr ls)) 
09        (loop (cdr ls) (car ls)))
10   ((eq? (car ls) current) 
11        (loop (cdr ls) current))
12   (else (cons (car ls) 
13        (loop (cdr ls) (car ls)))))))

第02行:您正在使用let语法的特殊形式来创建一个命名过程,然后您可以在let中调用它。您在循环ls中定义(令人困惑)变量,其名称与循环外部的变量完全相同,为内部变量提供外部变量的初始值。您还要定义第二个参数current,您将给出初始值#f

第04行开始cond

第05行(我通过引用空列表进行了更正以使其工作)如果ls为空,则返回空列表。这将停止该过程并展开堆栈。

第06行检查cdr是否为空,表示您正在操作列表的最后一个元素。如果确实如此,则转到第07行,如果car的{​​{1}}等于ls,则返回空列表,或者返回current。这也结束了程序并展开堆栈。

第08-09行连续查找重复项,如果是,则使用ls作为新列表并将cdr作为car来调用循环过程。

第10-11行检查current是否等于car,如果是,则调用current的循环过程(再次向下迭代列表)和{{1} }。

如果没有满足这些条件,则第12-13行将cdr创建一个新列表 - current cons,其结果是调用{{1} car lslet loop上创建的cdr程序。

如果程序按预期工作,则应该返回ls

这是一个可以正常运行的程序:

car