Это должно сделать ...
(defun take-while (list test)
(and list (funcall test (car list))
(cons (car list) (take-while (cdr list) test))))
(take-while '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) (lambda (x) (< x 10)))
--> (1 2 3 4 5 6 7 8 9)
Однако эта "естественная" реализация не является хвостовой рекурсивной и может привести к сбою для больших списков.
Явный подход push-nreverse (aобщий шаблон) может быть
(defun take-while (list test)
(do ((res nil))
((or (null list) (not (funcall test (car list))))
(nreverse res))
(push (car list) res)
(setf list (cdr list))))
Рекурсивный (но хвостовой рекурсивный, поэтому вероятно нормально с большинством реализаций CL) IMO может быть следующим:
(defun take-while (list test)
(labels ((rec (res x)
(if (and x (funcall test (car x)))
(rec (cons (car x) res) (cdr x))
(nreverse res))))
(rec nil list)))
Обратите внимание, что, однако, не гарантируется, что обычная реализация lisp будет обрабатывать оптимизацию хвостового вызова.