I did Graham Common Lisp Chapter 5 Exercise 5, which requires a function that takes an object X and a vector V, and returns a list of all the objects that immediately precede X in V.
It works like:
> (preceders
(#\c
I made a recursive version:
(defun preceders (obj vec &optional (result nil) &key (startt 0))
(let ((l (length vec)))
(cond ((null (position obj vec :start startt :end l)) result)
((= (position obj vec :start startt :end l) 0)
(preceders obj vec result
:startt (1+ (position obj vec :start startt :end l))))
((> (position obj vec :start startt :end l) 0)
(cons (elt vec (1- (position obj vec :start startt :end l)))
(preceders obj vec result
:startt (1+ (position obj vec
:start startt
:end l))))))))
This works correctly, but my teachers give me the following criticism:
"This causes lengths many times. Not so bad with vectors, but still unnecessary. More efficient and more flexible (for the user) code should define this as other sequence processing functions. Use: start and: end keyword parameters, as others do "sequence functions, with the same initial default values. The length must be called no more than once."
Common Lisp google, , , : , ": start : end keyword parameters", , " ". , , , , , . !
UPDATE:
, , :
(defun preceders (obj vec
&optional (result nil)
&key (start 0) (end (length vec)) (test
(let ((pos (position obj vec :start start :end end :test test)))
(cond ((null pos) result)
((zerop pos) (preceders obj vec result
:start (1+ pos) :end end :test test))
(t (preceders obj vec (cons (elt vec (1- pos)) result)
:start (1+ pos) :end end :test test)))))
:
" , , , , IF COND."
, :
(defun preceders (obj vec)
(do ((i 0 (1+ i))
(r nil (if (and (eql (aref vec i) obj)
(> i 0))
(cons (aref vec (1- i)) r)
r)))
((eql i (length vec)) (reverse r))))
" DO > 0"
, , !
!