Pregunta

Estoy tratando de ejecutar el código de trazado de rayos del ANSI Common Lisp de Paul Graham en OS X usando SLIME con OpenMCL (bueno, ahora llamado CCL). En ese código, hay una constante definida cuyo valor es una estructura, y cuando llamo a slime-compile-and-load-file o slime-compile-defun en cualquier función que usa la constante, recibo un mensaje de error:

  

No se ha definido ningún método MAKE-LOAD-FORM   para #S (PUNTO: X 0                                                    : Y 0                                                    : Z 200) [Condición del tipo   ERROR SIMPLE]

Encontré una publicación explicando la complicación y otro lamentando, pero qué necesita agregarse al código para negociar este aspecto de OpenMCL?

¿Fue útil?

Solución

Cuando los OBJETOS DE ESTRUCTURA (y algunos otros tipos de objetos) aparecen como literales, los objetos constantes en el código que procesa COMPILE-FILE, COMPILE-FILE necesitan saber cómo organizar eso, cuando se carga el archivo binario resultante, un "equivalente" Se crea el objeto. Hay muchas definiciones posibles de "equivalente" : a veces, es importante que los componentes del objeto cargado compartan estructura con otros objetos, a veces es importante que la inicialización ocurra de cierta manera, y a veces ninguna de estas cosas es importante. Para determinar cómo recrear el objeto constante, COMPILE-FILE llama a la función genérica MAKE-LOAD-FORM; Este comportamiento debe describirse en cualquier referencia de CL o tutorial. (Una referencia o tutorial también debe tener en cuenta que la implementación no puede definir los métodos predeterminados MAKE-LOAD-FORM que serían aplicables a todas las instancias de STRUCTURE-CLASS o STANDARD-CLASS, y también debería tener en cuenta que MAKE-LOAD-FORM-SAVING -SLOTS es una función conveniente para usar en los métodos MAKE-LOAD-FORM para objetos cuya inicialización no necesita ser complicada, por ejemplo:

(defmethod make-load-form ((p point) &optional env)
  (declare (ignore env))
  (make-load-form-saving-slots p))

Tenga en cuenta que ese método debe definirse en tiempo de compilación, de modo que COMPILE-FILE pueda llamarlo para determinar cómo guardar el objeto POINT constante.

Nada de esto es específico de CCL. Lo que podría ser es la cuestión de qué cosas son constantes, objetos literales y qué cosas no lo son.

En código como:

(defconstant a-point (make-point :x 0 :y 0 :z 200))

(defun return-a-point () a-point)

el compilador permitió (pero no es obligatorio) sustituir el valor de A-POINT por la referencia a este en la función RETURN-A-POINT. (Si el compilador lo hace, eso sería significa que hay un objeto POINT literal / constante en el código que se está compilando, y COMPILE-FILE necesitaría llamar a MAKE-LOAD-FORM para determinar cómo se debe guardar y cargar el objeto; si el compilador no realiza esta sustitución, entonces no es necesario llamar a MAKE-LOAD-FORM en este ejemplo).

Si una implementación hace este tipo de sustitución o no, depende de la implementación. La especificación también lo deja sin especificar en cuanto a si el formulario de valor en un formulario DEFCONSTANT se evalúa en tiempo de compilación, tiempo de carga, o ambos, y señala que se debe tener cuidado (por parte del usuario) para garantizar que la expresión siempre evalúe el mismo valor.

CCL generalmente intenta evaluar la forma del valor DEFCONSTANT en tiempo de compilación, y es bastante agresivo al sustituir los valores de las constantes nombradas por referencias a ellas; en algunos casos, esto significa que deben definirse los métodos MAKE-LOAD-FORM en las clases de valores de las constantes. Otras implementaciones pueden estar menos dispuestas a hacer esta sustitución para algunos tipos de objetos. Ambas estrategias son correctas, y el código portátil no puede suponer qué estrategias se están siguiendo (aunque mucho código supuestamente portátil seguramente hace tales suposiciones).

El tratamiento diferente de las cosas definidas por DEFCONSTANT parece ser la causa más probable de este tipo de cosas (llamadas inesperadas a MAKE-LOAD-FORM que nadie se molestó en definir). Uno puede evitar algunos de estos problemas de una manera que debería ser portátil haciendo:

(defconstant a-point (make-point :x 0 :y 0 :z 200))

(defun return-a-point () (load-time-value (symbol-value 'a-point)))

Esto tendrá un efecto similar a simplemente permitir que una implementación que quiera hacerlo (como lo hace CCL) realice una sustitución constante, pero el uso de LOAD-TIME-VALUE garantizará que el valor constante se evalúe solo en la carga tiempo (y que MAKE-LOAD-FORM no estará involucrado)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top