eintr: Keep
Recursive Pattern: _keep_
.........................
A third recursive pattern is called the ‘keep’ pattern. In the ‘keep’
recursive pattern, each element of a list is tested; the element is
acted on and the results are kept only if the element meets a criterion.
Again, this is very like the ‘every’ pattern, except the element is
skipped unless it meets a criterion.
The pattern has three parts:
• If a list be empty, return ‘nil’.
• Else, if the beginning of the list (the CAR of the list) passes a
test
− act on that element and combine it, using ‘cons’ with
− a recursive call by the function on the rest (the CDR) of the
list.
• Otherwise, if the beginning of the list (the CAR of the list) fails
the test
− skip on that element,
− and, recursively call the function on the rest (the CDR) of
the list.
Here is an example that uses ‘cond’:
(defun keep-three-letter-words (word-list)
"Keep three letter words in WORD-LIST."
(cond
;; First do-again-test: stop-condition
((not word-list) nil)
;; Second do-again-test: when to act
((eq 3 (length (symbol-name (car word-list))))
;; combine acted-on element with recursive call on shorter list
(cons (car word-list) (keep-three-letter-words (cdr word-list))))
;; Third do-again-test: when to skip element;
;; recursively call shorter list with next-step expression
(t (keep-three-letter-words (cdr word-list)))))
(keep-three-letter-words '(one two three four five six))
⇒ (one two six)
It goes without saying that you need not use ‘nil’ as the test for
when to stop; and you can, of course, combine these patterns.