¿Es posible definir dos funciones que se llaman entre sí en Common LISP sin recibir una advertencia de estilo? Mi mejor idea para resolver ese problema es darle a una de esas funciones la segunda como argumento, pero no creo que esa idea sea muy elegante.

1
Alicja123 21 abr. 2020 a las 14:04

3 respuestas

La mejor respuesta

Common Lisp define unidades de compilación , e incluso puede especificar manualmente el alcance de una unidad de compilación utilizando WITH-COMPILATION-UNIT.

Por ejemplo, cuando llama a COMPILE-FILE, el archivo completo representa una unidad de compilación: los compiladores generalmente difieren las advertencias al final del archivo, lo que significa que si define correctamente dos funciones recursivas mutuamente, no habrá una advertencia.

Otra posibilidad es realizar una declaración directa:

(declaim (ftype function f))
(defun g () (f))
(defun f () (g))

El primer declaim indica que f debe considerarse fbound (el símbolo está enlazado en el espacio de nombres de la función), suprimiendo las advertencias en el punto de uso durante la compilación.

4
coredump 21 abr. 2020 a las 15:53

Puede definir dos funciones recursivas mutuamente sin una advertencia de estilo de una manera un poco complicada, dado que defun no es necesario que aparezca en el nivel superior (consulte Common Lisp the Language, 2nd Edition):

X3J13 votó en marzo de 1989 (DEFINING-MACROS-NON-TOP-LEVEL) para aclarar que, si bien las formas definitorias normalmente aparecen en el nivel superior, es significativo ubicarlas en contextos de nivel no superior; defun debe definir la función dentro del entorno léxico adjunto, no dentro del entorno léxico nulo.

Un ejemplo es utilizar el operador especial labels (manual), que permite la definición de funciones recursivas mutuamente:

CL-USER> (labels ((f (x)
                    (cond ((> x 0) (g (1- x)))
                          ((= x 0) x)
                          (t (g (1+ x)))))
                  (g (y)
                    (if (= y 0)
                        0
                        (f y))))
           (defun f(x) (funcall #'f x))
           (defun g(x) (funcall #'g x)))
G
CL-USER> (f 3)
0
CL-USER> (g 3)
0
1
Renzo 21 abr. 2020 a las 15:41

Eso es por supuesto posible. Solo debes tener cuidado de no crear un bucle infinito. Entonces, lo mismo se aplica aquí que para la recursividad (necesita un caso de terminación).

Por cierto, SBCL advierte cuando una función llama a una función indefinida.

Pozdrowienia!

0
wasserwerk 21 abr. 2020 a las 13:33