Search code examples
schemelisp

I would like to understand each line how this code removes duplicates in a list , so this is the list (a b a a a c c) gives (a b)


here is the code and its working fine on scheme 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)))) )))

and here is what i tried

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

and got (a b)

I want to know how each line of the code works


Solution

  • I've added line numbers and fixed your indentation to make it easier to explain:

    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)))))))
    

    Line 02: You are using a special form of the let syntax to create a named procedure that you can then call from within the let. You are defining (confusingly) a variable inside the loop ls with the exact same name as a variable outside of the loop, giving the internal variable the initial value of the external one. You are also defining a second parameter, current that you are giving the initial value of #f.

    Line 04 starts a cond.

    Line 05 (I corrected it so it would work by quoting the empty list) returns an empty list if ls is null. This stops the procedure and unwinds the stack.

    Line 06 checks if the cdr is null, indicating that you are operating on the last element of the list. If that is true, you go to line 07 and either return an empty list if the car of ls is equal to current, or you return ls. This also ends the procedure and unwinds the stack.

    Lines 08-09 look for duplicates in a row and if so it calls the loop procedure using the cdr as the new list and the car as the current.

    Lines 10-11 check if the car is equal to current and if so it calls the loop procedure with the cdr (again iterating down the list) and current.

    If none of those conditions are met, lines 12-13 will create a new list by cons-ing the car of ls with the result of calling the let-created loop procedure on the cdr of ls and the car of ls.

    If the procedure worked as intended, it should have returned '(a b c).

    Here's one that works as I think your program is intended to work:

    (define rdup
      (lambda (l)
       (reverse (let loop ((lst l)
                   (c '()))
          (cond
            ((null? lst) c)
            (else
             (if (member (car lst) c)
                 (loop (cdr lst) c)
                 (loop (cdr lst) (cons (car lst) c)))))))))