He hecho el Graham Common Lisp Capítulo 5 Ejercicio 5, que requiere una función que toma un objeto X y un vector V, y devuelve una lista de todos los objetos que preceden inmediatamente a X en V.Refinamiento de función lisp
funciona así:
> (preceders #\a "abracadabra")
(#\C#\d #r)
he hecho la versión recursiva:
(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))))))))
funciona correctamente, pero mis maestros me da la siguiente crítica:
"Esto llama longitud repetidamente. No es tan malo con los vectores, pero sigue siendo innecesario. Un código más eficiente y más flexible (para el usuario) es definir esto como otras funciones de procesamiento de secuencia. Utilice: parámetros de palabras clave de inicio y fin, como lo hacen las otras funciones de secuencia, con los mismos valores iniciales predeterminados. la longitud debería llamarse como mucho una vez. "
Estoy consultando el libro de texto de Common Lisp y google, pero parece que hay poca ayuda en este aspecto: no sé a qué se refiere con" using: start y: finalice los parámetros de palabra clave ", y no tengo ni idea de cómo" llamar por única vez ". Les agradecería si pudieran darme una idea de cómo refinar mi código para cumplir con el requisito que mi profesor publicó. Gracias una gran cantidad
ACTUALIZACIÓN:
Hola chicos, ahora han llegado con el siguiente código:
(defun preceders (obj vec
&optional (result nil)
&key (start 0) (end (length vec)) (test #'eql))
(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)))))
me sale esa crítica:
"Cuando se tiene una llamada recursiva complejo que se repite de forma idéntica en más de una rama, a menudo es más fácil de hacer la llamada primera, guardarlo en una variable local, y luego usar la variable de una manera mucho más simple si o COND "
Además, para mi versión iterativa de la función:.
(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))))
consigo la crítica
"Comience el DO en un punto mejor y elimine la prueba> 0 repetida"
¿Podría compartir sus ideas conmigo, creo que este es mi paso final hacia el éxito? ¡Muchas gracias!
Gracias Rainer, muy útil para la sintaxis, es muy difícil encontrar en la web una definición tan precisa para las funciones de procesamiento de secuencia, así que muchas gracias. Ahora estoy trabajando para que mi código sea mucho más simple, y lo haré. deja que ustedes sepan de lo que mi profesor me criticará. – Kevin