简体   繁体   中英

Reversing a list error

I'm learning DrRacket, and I need to write a program that reverses a list. I have the below, and it's reversing the numbers, but somehow nesting them inside lists or something.

(define (reverse-list lon)
  (if (empty? lon)
      empty
      (cons (reverse-list (rest lon))
            (cons (first lon)
                  empty))))

Output of (reverse-list (list 1 2 3 4)):

(list (list (list (list empty 4) 3) 2) 1)

Anyone know why the output isn't just coming out as one list?

Thanks for the help!

A cons has two cells. car and cdr . A cell can be displayed as (a . b) where a and b can be anything.

There is an alternative representation to a pair. If b is either another pair or the empty list you can just replace . b ) . b ) with b without the initial ( . Thus:

(a . ())             ; ==> (a)
(a . (b . c))        ; ==> (a b . c)
(a . (b . (c . ()))) ; ==> (a b c)

Now for your code. Imagine you try it with (1 2 3 4) (or (1 . (2 . (3 . (4 . ())))) to be precise). Using substitution rules we calculate exactly what your procedure does:

(reverse-list '(1 . (2 . (3 . (4 . ())))))                   ; ==>
(if (empty? '(1 . (2 . (3 . (4 . ())))))
    empty 
    (cons (reverse-list (rest '(1 . (2 . (3 . (4 . ()))))))
          (cons (first '(1 . (2 . (3 . (4 . ()))))) 
                empty)))                                      ; ==>
(if #f
    empty 
    (cons (reverse-list (rest '(1 . (2 . (3 . (4 . ()))))))
          (cons (first '(1 . (2 . (3 . (4 . ()))))) 
                empty)))                                      ; ==>

(cons (reverse-list '(2 . (3 . (4 . ()))))
      (cons 1 empty))                                      ; ==>

(cons (cons (reverse-list '(3 . (4 . ())))
            (cons 2 empty))
      (cons 1 empty))                                      ; ==>

(cons (cons (cons (reverse-list '(4 . ()))
                  (cons 3 empty))
            (cons 2 empty))
      (cons 1 empty))                                      ; ==>

(cons (cons (cons (cons (reverse-list '())
                        (cons 4 empty))
                  (cons 3 empty))
            (cons 2 empty))
      (cons 1 empty))                                      ; ==>

(cons (cons (cons (cons '()
                        (cons 4 empty))
                  (cons 3 empty))
            (cons 2 empty))
      (cons 1 empty))                                      ; ==>

((((() . (4 . ())) . (3 . ())) . (2 . ())) . (1 . ()))     ; ==>
((((() . (4)) . (3)) . (2)) . (1))                         ; ==>
((((() 4) 3) 2) 1)

Now. a True reversed list would have looked like this in dotted notation:

(4 . (3 . (2 . (1 . ())))) ; ==> (4 3 2 1)

There is no way around it. You need to get quite intimate with cons and know you way around how the different ways to construct them gets displayed. A hint would be that almost every list gets created from the end towards the beginning and iterated from the beginning to the end.

Nice to see you have solved your own problem. However I feel I should pick a little since reversing a list is realy building one on your way iterating.

(define (reverse-list lon)
  ;; iterative helper procedure
  (define (aux lon acc)
    (if (empty? lon)
        acc
        (aux (rest lon) 
             (cons (first lon) acc))))
  ;; use helper
  (aux lon empty))

(reverse-list '(1 2 3 4)) ; ==> (4 3 2 1)

As you can see we iterate from beginning to end. As we do that we cons the current element to the accumulated list so far and that operation is from end to beginning. Ei the last added element will be the first in the result. The nice thing about this is that we use one new cell for each cell processed and it's becomes part of the end result. For each use of append you copy the first argument so a n element list gets (apply + (range n)) unnecessary cells allocated.

A more seasoned Schemer would use a named let to do both the local procedure and call in one go:

(define (reverse-list lon)
  (let aux ((lon lon) (acc empty))
    (if (empty? lon)
        acc
        (aux (rest lon) 
             (cons (first lon) acc)))))

So, what ended up working was just replacing the first cons with an append to stop the list nesting.

(define (reverse-list lon)
  (if (empty? lon) empty (append (reverse-list (rest lon)) (cons (first lon) empty))))

Problems solved, thanks for the help though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM