viernes, 21 de agosto de 2009

Higiene en tu macro

El modelo de entornos

A la hora de sustituir nombres de variables por valores hay dos formas de proceder. La primera es el modelo de sustituciones propio del lambda-cálculo. Si x vale 3 cambio la x por el 3. Este modelo es válido cuando la x siempre vale 3. Si quiero que la x valga otra cosa necesito saber cuándo vale 3 y cuándo vale otra cosa.

En este punto entra la idea de entorno. Un entorno no es más que una serie de nombres con sus valores correspondientes. Podría ser algo como

x=3
y="hola"
z=λx.f(x)

En la variable z hay una cosa interesante. ¡Hay una x! Y la x valía 3... a no ser que esté en otro entorno. Eso es lo que ocurre. El lambda-cálculo se integra en el modelo de entornos haciendo que las abstracciones lambda tengan un pequeñito entorno dentro de ellas. Este entorno local se crea cuando se aplica la abstracción. Al calcular

z(7)

lo que ocurre es que creo un entorno nuevo donde los parámetros (la x) se vinculan a los argumentos (el 7)

x=7

Y, entonces, sustituyo:

z(7)=f(7)

Ahora tenemos otro problema: ¡f no está en ninguno de nuestros entornos! Cierto. Debe existir otro entorno donde esté f definida y ese entorno debe estar visible desde el entorno local de la lambda. Así pues, cada entorno puede tener un entorno padre donde busque los nombres que no encuentre en él mismo.

Los tres entornos, las funciones

Existen tres entornos que participan a la hora de calcular el valor de una función. Son:

  • El entorno de uso. Es decir, donde se realiza la aplicación de la función con sus argumentos.
  • El entorno local. Es ese donde se vinculan los argumentos a los parámetros. Es temporal, en cuanto se acabe de calcular la función, se olvida.
  • El entorno de definición. Es donde se creó la función, la abstracción lambda. Es donde está la f del ejemplo anterior.

En una función, el entorno padre del entorno local es el entorno de definición. Esto es lo que se llama la clausura léxica. Muchos lenguajes no soportan que un entorno tenga padre y, por tanto, usan los nombres de un entorno global.

El entorno local protege el entorno de uso de agresiones. Si una función tiene que usar un nombre para un cálculo parcial, ese nombre estará en el entorno local y morirá cuando la función termine de calcular. Si eso no fuera así tendríamos el siguiente problema.

funcion f(x) :=
{
 //Creo aquí un nombre que debería ser
 //temporal y oculto en f(x)
 y=x*x;
 retorna 2*y;
}
//Creo aquí un nombre que no tiene nada que ver
//con el anterior y porque estamos en otro entorno
y=7;
f(4);
//¿Cuánto vale aquí y?

Si y vale 7 significa que hemos protegido la y de fuera de f(x) de la y de dentro que vale 4*4=16.

Y las macros higiénicas

El no proteger estos símbolos da origen a lo que se llama falta de higiene porque ensuciamos los símbolos de fuera. Es una característica de los sistemas de macro tradicionales. Una macro es un conjunto de expresiones que se ponen, sin más miramientos, donde aparece el nombre de una macro.

Como ejemplo, una macro m definida así:

macro m :=
{
y=3; //Defino la y dentro del código.
f(z);
}

Y usada en un código así:

z=7;
m;
print(y); //Debería dar error, no he definido ninguna y en este código.

Da este resultado:

z=7;
y=3; //Contamino el entorno de fuera desde la macro.
f(z); //Uso la z de fuera en la macro ¿es esto deseable?.

print(y); //Captura la y de la macro en vez de estar sin definir.

Es completamente antihigiénico porque introducimos el símbolo y en el entorno de uso.

Las macros higiénicas evitan eso usando, como las funciones, un entorno local. Sería entonces algo parecido a:

z=7;
{
y=3; //No contamino el entorno de fuera
f(z); //¡¡No es una función porque puedo usar la z!!

}
print(y);

Las macros higiénicas pueden verse como una función en el que el entorno padre del entorno local no es el entorno de definición, sino el de uso.

0 comentarios:

Publicar un comentario