Skip to main content

revappend, nreconc

revappend, nreconc Function

Syntax:

revappend list tail → result-list

nreconc list tail → result-list

Arguments and Values:

list—a proper list.

tail—an object.

result-list—an object.

Description:

revappend constructs a copy2 of list, but with the elements in reverse order. It then appends (as if by nconc) the tail to that reversed list and returns the result.

nreconc reverses the order of elements in list (as if by nreverse). It then appends (as if by nconc) the tail to that reversed list and returns the result.

The resulting list shares list structure with tail.

revappend, nreconc

Examples:

(let ((list-1 (list 1 2 3)) 
(list-2 (list ’a ’b ’c)))
(print (revappend list-1 list-2))
(print (equal list-1 ’(1 2 3)))
(print (equal list-2 ’(a b c))))
(3 2 1 A B C)
▷ T
▷ T
→ T
(revappend(1 2 3)())(3 2 1)
(revappend(1 2 3)(a . b))(3 2 1 A . B)
(revappend()(a b c))(A B C)
(revappend(1 2 3) ’a)(3 2 1 . A)
(revappend() ’a) → A ;degenerate case
(let ((list-1(1 2 3))
(list-2(a b c)))
(print (nreconc list-1 list-2))
(print (equal list-1 ’(1 2 3)))
(print (equal list-2 ’(a b c))))
(3 2 1 A B C)
▷ NIL
▷ T
→ T

Side Effects:

revappend does not modify either of its arguments. nreconc is permitted to modify list but not tail.

Although it might be implemented differently, nreconc is constrained to have side-effect behavior equivalent to:

(nconc (nreverse list) tail)

See Also:

reverse, nreverse, nconc

Notes:

The following functional equivalences are true, although good implementations will typically use a faster algorithm for achieving the same effect:

(revappend list tail) (nconc (reverse list) tail)

(nreconc list tail) (nconc (nreverse list) tail)

Expanded Reference: revappend, nreconc

Basic revappend usage

revappend reverses the first list and appends the second list (tail) to the result. It is equivalent to (nconc (reverse list) tail) but typically more efficient.

(revappend '(1 2 3) '(4 5 6))
=> (3 2 1 4 5 6)

(revappend '(a b c) '())
=> (C B A)

revappend does not modify its arguments

(let ((lst '(1 2 3))
(tail '(a b)))
(revappend lst tail)
(values lst tail))
=> (1 2 3)
=> (A B)

Non-list tail values

The tail argument does not have to be a list. It becomes the cdr of the last cons in the result, creating a dotted list.

(revappend '(1 2 3) 'end)
=> (3 2 1 . END)

(revappend '() 'x)
=> X

nreconc is the destructive version

nreconc is like revappend but may destructively modify the first list. The tail is never modified.

(let ((lst (list 1 2 3)))
(nreconc lst '(a b c)))
=> (3 2 1 A B C)

Practical use: accumulate-and-reverse pattern

revappend is commonly used in the pattern of accumulating results in reverse order and then reversing at the end, appending remaining elements.

;; Take elements while they satisfy a predicate, return them
;; in order along with the rest of the list
(defun take-while (pred lst)
(do ((rest lst (cdr rest))
(acc '() (cons (car rest) acc)))
((or (null rest) (not (funcall pred (car rest))))
(values (revappend acc '()) rest))))

(take-while #'evenp '(2 4 6 7 8))
=> (2 4 6)
=> (7 8)