Para llegar alcance y cierres léxica correcta en un intérprete, todo lo que tiene que hacer es seguir estas reglas:
- En su intérprete, las variables siempre se buscan en una tabla de entorno aprobada en la persona que llama/mantenido como una variable, no alguna pila env global. Es decir,
eval(expression, env) => value
.
- Cuando el código interpretado llama a una función, el entorno es NOT pasado a esa función.
apply(function, arguments) => value
.
- Cuando se invoca una función interpretada, el entorno en el que se evalúa su cuerpo es el entorno en el que se realizó la definición de la función y no tiene nada que ver con la persona que llama. Entonces, si tiene una función local, entonces es un cierre, es decir, una estructura de datos que contiene los campos
{function definition, env-at-definition-time}
.
Para ampliar ese último bit en Python-ish sintaxis:
x = 1
return lambda y: x + y
es ejecutado como si fuera
x = 1
return makeClosure(<AST for "lambda y: x + y">, {"x": x})
en el que el segundo argumento dict puede ser justo la corriente de env en lugar de una estructura de datos construida en ese momento. (Por otro lado, conservar todo el env en lugar de solo las variables cerradas puede causar fugas de memoria.)
Deberías leer * Fundamentos de los lenguajes de programación * http://www.cs.indiana.edu/eopl/ –