Soy un principiante de Lisp. Estoy intentando memorizar una función recursiva para calcular el número de términos en un Collatz sequence (para el problema 14 en Project Euler). Mi código hasta el momento es:¿Cómo puedo memorizar una función recursiva en Lisp?
(defun collatz-steps (n)
(if (= 1 n) 0
(if (evenp n)
(1+ (collatz-steps (/ n 2)))
(1+ (collatz-steps (1+ (* 3 n)))))))
(defun p14()
(defvar m-collatz-steps (memoize #'collatz-steps))
(let
((maxsteps (funcall m-collatz-steps 2))
(n 2)
(steps))
(loop for i from 1 to 1000000
do
(setq steps (funcall m-collatz-steps i))
(cond
((> steps maxsteps)
(setq maxsteps steps)
(setq n i))
(t())))
n))
(defun memoize (fn)
(let ((cache (make-hash-table :test #'equal)))
#'(lambda (&rest args)
(multiple-value-bind
(result exists)
(gethash args cache)
(if exists
result
(setf (gethash args cache)
(apply fn args)))))))
La función memoize es la misma que la dada en el libro On Lisp.
Este código en realidad no da ninguna aceleración en comparación con la versión no memorable. Creo que se debe a las llamadas recursivas que llaman a la versión no memorable de la función, que en cierto modo frustra el propósito. En ese caso, ¿cuál es la forma correcta de hacer la memorización aquí? ¿Hay alguna manera de hacer que todas las llamadas a la función original llamen a la versión modificada, eliminando la necesidad del símbolo especial m-collatz-steps?
EDIT: Se ha corregido el código para tener
(defvar m-collatz-steps (memoize #'collatz-steps))
que es lo que tenía en mi código. antes de la edición que había erróneamente puesto:
(defvar collatz-steps (memoize #'collatz-steps))
Al ver que el error me dio otra idea, y yo probamos el uso de esta última en sí defvar y el cambio de las llamadas recursivas a
(1+ (funcall collatz-steps (/ n 2)))
(1+ (funcall collatz-steps (1+ (* 3 n))))
Esto parece llevar a cabo la memorización (aceleración de aproximadamente 60 segundos a 1.5 segundos), pero requiere cambiar la función original. ¿Hay una solución más limpia que no implique cambiar la función original?
Esto funcionaría si llama al setf después de la definición de función –