resueltos programa principiantes para mundo hola estructura ejercicios ejemplos características caracteristicas lisp common-lisp

programa - lisp pdf



¿Cómo es Lisp dinámico y compilado? (3)

Para que un lenguaje pueda manipular, modificar y generar código, ¿no es un requisito para ser interpretado?

No.

¿Es posible que un lenguaje se compile por completo y aún sea dinámico?

Sí.

¿O me estoy perdiendo algo?

Sí.

¿Qué está haciendo Lisp que le permite ser compilado y dinámico?

Se compila sobre la marcha, al igual que la mayoría de las implementaciones de Java y PyPy.

No entiendo cómo Lisp puede ser compilado y dinámico. Para que un lenguaje pueda manipular, modificar y generar código, ¿no es un requisito para ser interpretado? ¿Es posible que un lenguaje se compile por completo y aún sea dinámico? ¿O me estoy perdiendo algo? ¿Qué está haciendo Lisp que le permite ser compilado y dinámico?


Lisp es una amplia familia de lenguajes e implementaciones.

Dinámico en el contexto de Lisp significa que el código tiene cierta flexibilidad en tiempo de ejecución. Puede ser cambiado o reemplazado por ejemplo.

Compilación en Lisp

A menudo, las implementaciones de Lisp tienen un compilador disponible en tiempo de ejecución. Cuando este compilador es incremental , no necesita programas completos, pero puede compilar formularios Lisp individuales. Así llamamos al compilador para soportar compilación incremental .

Tenga en cuenta que la mayoría de los compiladores Lisp no son compiladores Just In Time . Usted como programador puede invocar el compilador, por ejemplo en Common Lisp con las funciones COMPILE y COMPILE-FILE . Luego se compila el código Lisp.

Además, la mayoría de los sistemas Lisp con compilador e intérprete permiten que la ejecución del código interpretado y compilado se mezcle libremente.

En Common Lisp, al compilador también se le puede indicar qué tan dinámico debe ser el código compilado. Un compilador Lisp más avanzado como el compilador de SBCL (o muchos otros) puede generar un código diferente.

Ejemplo

(defun foo (a) (bar a 3))

Por encima de la función foo llama a la bar funciones.

Si tenemos una bar funciones y la redefinimos, generalmente esperamos que en Lisp la nueva bar funciones sea llamada por foo . No tenemos que recompilar foo .

Echemos un vistazo a GNU CLISP . Se compila a un código byte. No es un código de máquina nativo, pero para nuestro propósito aquí es más fácil de leer.

CL-USER 1 > (defun foo (a) (bar a 3)) FOO CL-USER 2 > (compile ''foo) FOO NIL NIL [3]> (disassemble #''foo) Disassembly of function FOO (CONST 0) = 3 (CONST 1) = BAR 1 required argument 0 optional arguments No rest parameter No keyword parameters 4 byte-code instructions: 0 (LOAD&PUSH 1) 1 (CONST&PUSH 0) ; 3 2 (CALL2 1) ; BAR 4 (SKIP&RET 2)

Búsqueda en tiempo de ejecución

Así que ya ves que la llamada a BAR hace una búsqueda en tiempo de ejecución. Mira el símbolo BAR y luego llama a la función del símbolo. Así, la tabla de símbolos sirve como un registro para funciones globales.

Esta búsqueda en tiempo de ejecución en combinación con un compilador incremental, disponible en tiempo de ejecución, nos permite generar código Lisp, compilarlo, cargarlo en el sistema Lisp actual y hacer que modifique el programa Lisp pieza por pieza.

Esto se hace mediante el uso de una indirección. En el tiempo de ejecución, el sistema Lisp busca la función actual llamada bar . Pero tenga en cuenta, esto no tiene nada que ver con la compilación o la interpretación. Si su compilador compila foo y el código generado usa este mecanismo, entonces es dinámico . Por lo tanto, tendría la sobrecarga de búsqueda tanto en el código interpretado como en el compilado.

Desde la década de los 70, la comunidad de Lisp hizo un gran esfuerzo para hacer que la semántica del compilador y el intérprete sea lo más similar posible.

Un lenguaje como Common Lisp también permite al compilador hacer que el código compilado sea menos dinámico. Por ejemplo, al no buscar funciones en tiempo de ejecución para ciertas partes del código.


Se puede compilar y dinamizar al mismo tiempo porque está enlazado tarde. Puede ejecutar una lista de funciones y argumentos y luego agregarle algo y luego ejecutarlo nuevamente. Básicamente, cada parte del código puede ejecutarse no solo funciones completas.