简体   繁体   中英

LISP: take an arbitrary s-expression and reverse every cons node (car and cdr of a node) recursively

So in lisp a list is a collection of cons nodes, each node has two parts to it. The car of the node and the cdr of that node, how would I go about reversing each cons node?

Using reduce:

(defun reverse-conses (list)
  (reduce (lambda (x acc) (cons acc x)) list :initial-value nil :from-end t))

Recursively:

(defun reverse-conses (list)
  (if (null list) nil
      (cons (reverse-conses (cdr list)) (car list))))

I'm starting with a single function that swaps a cons cell.

(defun swap-cons (cns)
  (cons (cdr cns)
        (car cns)))

Let's test it:

> (swap-cons (cons 1 2))
(2 . 1)
> (swap-cons (cons 1 (cons 2 3)))
((2 . 3) . 1)

So this works. Now we just need to map this function over the input list

(defun swap-conses (lst)
  (mapcar #'swap-cons
       lst))

> (swap-conses '((1 . 2)))
((2 . 1))
> (swap-conses '((1 . 2) (3 . 4)))
((2 . 1) (4 . 3))
> (swap-conses '((1 2)))
(((2) . 1))
> (swap-conses '((1 . 2) (3 4) (5 6 7)))
((2 . 1) ((4) . 3) ((6 7) . 5))

To recursively go through a whole tree and swap car and cdr you can do something like this:

(defun reverse-conses (tree)
  (if (consp tree)
      (cons (reverse-conses (cdr tree))
            (reverse-conses (car tree)))
      tree))

(reverse-conses (cons 1 2))   ; ==> (2 . 1)
(reverse-conses '(1 2 3))     ; ==> (((nil . 3) . 2) . 1)
(reverse-conses '(1 (2 3) 4)) ; ==> (((nil . 4) (nil . 3) . 2) . 1)

Considering the argument can consist of improper lists there isn't a simpler solution to this.

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