programación programacion programa official net lenguajes investigador estructura creador creacion compiler common año apellido dynamic lisp common-lisp scoping lexical

dynamic - programacion - Alcance de Lisp común(dinámico frente a léxico)



lenguajes de programación lisp y prolog (1)

EDITAR: Cambié el código de ejemplo después de la primera respuesta porque se me ocurrió una versión simple que plantea las mismas preguntas.

Actualmente estoy aprendiendo las propiedades de alcance de Common Lisp. Después de pensar que tenía una comprensión sólida, decidí codificar algunos ejemplos de los que podía predecir el resultado, pero aparentemente estaba equivocado. Tengo tres preguntas, cada una relacionada con un ejemplo a continuación:

Ejemplo 1:

(defmethod fun1 (x) (print x) (fun2)) (defmethod fun2 () (print x)) (fun1 5)

Salida:

5 *** - EVAL: variable X has no value

Pregunta: Esto tiene sentido. x tiene un alcance estático y fun2 no tiene forma de encontrar el valor de x sin que se pase explícitamente.

Ejemplo 2:

(defvar x 100) (defmethod fun1 (x) (print x) (fun2)) (defmethod fun2 () (print x)) (fun1 5)

Salida:

5 5

Pregunta: No entiendo por qué x es repentinamente visible para fun2 con el valor que fun1 le dio, en lugar de tener un valor de 100 ...

Ejemplo 3:

(setf x 100) (defmethod fun1 (x) (print x) (fun2)) (defmethod fun2 () (print x)) (fun1 5)

Salida:

5 100

Pregunta: ¿Debería ignorar estos resultados ya que llamar a setf en una variable no declarada aparentemente no está definido? Esto pasa a ser lo que esperaría en mi segundo ejemplo ...

Cualquier idea sería muy apreciada...


Los efectos de establecer una variable no definida utilizando SETF no están definidos en ANSI Common Lisp.

DEFVAR definirá una variable especial. Esta declaración es global y también tiene efecto en los enlaces LET. Esa es la razón por la cual, por convención, estas variables se escriben como *foo* . Si alguna vez ha definido X con DEFVAR, se declara especial y no hay forma de declararlo léxico más tarde.

LET por defecto proporciona variables léxicas locales. Si la variable ya fue declarada especial (por ejemplo, debido a un DEFVAR), entonces solo crea un nuevo enlace dinámico local.

Actualizar

  • Ejemplo 1 .

Nada que ver.

  • Ejemplo 2

X ha sido declarado especial. Todos los usos de la variable X ahora usan enlace dinámico. Al llamar a la función, enlaza X a 5. Dinámicamente. Otras funciones ahora pueden acceder a este enlace dinámico y obtener ese valor.

  • Ejemplo 3

Este es un comportamiento indefinido en Common Lisp. Estás configurando una variable no declarada. Lo que sucede entonces depende de la implementación. Su implementación (la mayoría hace algo similar) establece el valor del símbolo de X en 100. En FUN1, X está ligado léxicamente. En FUN2, la evaluación de X recupera el valor del símbolo (o posiblemente el valor enlazado dinámicamente) de X.

Como ejemplo para una implementación que hizo (¿hace?) Algo más: la implementación de CMUCL también tendría que declarar X en el ejemplo 3 por defecto como especial. Establecer una variable indefinida también lo declara especial.

NOTA

En el código Common Lisp compatible con el estándar portátil, las variables globales se definen con DEFVAR y DEFPARAMETER. Ambos declaran que estas variables son especiales. TODOS los usos de estas variables ahora implican un enlace dinámico.

Recuerda:

((lambda (x) (sin x)) 10)

es básicamente lo mismo que

(let ((x 10)) (sin x))

Lo que significa que los enlaces variables en los enlaces LET y los enlaces variables en las llamadas a funciones funcionan de la misma manera. Si X hubiera sido declarado especial en algún lugar antes, ambos implicarían un enlace dinámico.

Esto se especifica en el estándar Common Lisp. Ver por ejemplo la explicación a la declaración ESPECIAL .