Deep-reverse for trees in Scheme (Lisp)

五迷三道 提交于 2019-12-14 01:12:08

问题


I have a deep reverse for a basic tree data structure in Scheme

(define (deep-reverse t)
  (cond ((null? t) '())
        ((not (pair? t)) t)  
        (else (cons (deep-reverse (cdr t)) (deep-reverse (car t))))))

(define stree (cons (list 1 2) (list 3 4)))
1 ]=> (deep-reverse stree)
;Value: (((() . 4) . 3) (() . 2) . 1)

I feel like a cleaner, better result would be:

(4 3 (2 1))

Can anyone provide some guidance as to where I'm going wrong in my deep-reverse function? Thank you.


回答1:


It's better to split the task into simple operations instead of trying to do all at once. What you want to achieve can be described like this: Reverse the current list itself, then deep-reverse all sublists in it (or the other way round, the order of the two steps doesn't really matter. I choose this order because it results in nicer formatting of the source code).

Now, there already is a function in the standard library for simply reversing a list, reverse. So all you need to do is to combine that with the recursion on those elements that are sublists:

(define (deep-reverse t)
  (map (lambda (x)
         (if (list? x)
             (deep-reverse x)
             x))
       (reverse t)))



回答2:


Try this:

(define (deep-reverse t)
  (let loop ((t t)
             (acc '()))
    (cond ((null? t) acc)
          ((not (pair? t)) t)
          (else (loop (cdr t)
                      (cons (loop (car t) '()) acc))))))

Call it like this:

(define stree (cons (list 1 2) (list 3 4)))
(deep-reverse stree)
> (4 3 (2 1))

For creating a reversed list, one technique is to accumulate the answer in a parameter (I usually call it acc). Since we're operating on a list of lists, the recursion has to be called on both the car and the cdr part of the list. Lastly, I'm using a named let as a shorthand for avoiding the creation of an extra function, but the same result could be obtained by defining a helper function with two parameters, the tree and the accumulator:

(define (deep-reverse t)
  (aux t '()))

(define (aux t acc)
  (cond ((null? t) acc)
        ((not (pair? t)) t)
        (else (aux (cdr t)
                   (cons (aux (car t) '()) acc)))))



回答3:


I think it better to reverse a list based on its element count: an empty list is reverse, a single element list is also reverted, more than 1 element is concatenation of the reverse of tail and head.

(defun deep-reverse (tree)
   (cond ((zerop (length tree)) nil)
         ((and (= 1 (length tree)) (atom (car tree))) tree)
         ((consp (car tree)) (append (deep-reverse (cdr tree)) 
                                     (list (deep-reverse (car tree)))))
         (t (append (deep-reverse (cdr tree)) (list (car tree))))))



回答4:


The following worked for me:

(define (deep-reverse tree)
  (define (deep-reverse-iter items acc)
    (cond
      ((null? items) acc)
      ((not (pair? items)) items)
      (else (deep-reverse-iter
        (cdr items)
        (cons (deep-reverse (car items)) acc)))))
  (deep-reverse-iter tree ()))

(define x (list (list 1 2) (list 3 4 (list 5 6))))

(newline)
(display (deep-reverse x))

It prints (((6 5) 4 3) (2 1)) as expected and uses the minimum of standard library functions: pair? to check if the tree is a cons and null? to check for an empty tree/list.

This solution for trees is a generalization of the reverse function for lists:

(define (reverse items)
  (define (reverse-iter items acc)
    (cond
      ((null? items) acc)
      ((not (pair? items)) items)
      (else (reverse-iter (cdr items) (cons (car items) acc)))))
  (reverse-iter items ()))

the difference being that deep-reverse is also applied to car items



来源:https://stackoverflow.com/questions/8797601/deep-reverse-for-trees-in-scheme-lisp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!