Devolver funciones

Es posible devolver funciones como un valor. De esta manera puede construir funciones que construyan otras funciones con propósitos específicos de acuerdo a ciertos parámetros. La parte complicada es determinar qué variables ve la función. La manera en que esto funciona en GEL es la siguiente: cuando una función devuelve otra función, todos los identificadores que referencia el cuerpo de la función que sale del ámbito son antepuestos al diccionario privado de la función devuelta. Por lo tanto, la función verá todas las variables que estaban en el ámbito cuando fue definida. Por ejemplo, la siguiente función devuelve una función que agrega 5 al valor de su argumento:

function f() = (
  k = 5;
  `(x) = (x+k)
)

Tenga en cuenta que la función agrega k a x. Podría utilizar esto como sigue:

g = f();
g(5)

And g(5) devuelve el valor 10.

Algo que conviene tener en cuenta es que el valor de k que se utiliza es el que se encuentra activo mientras f devuelve su valor. Por ejemplo:

function f() = (
  k := 5;
  function r(x) = (x+k);
  k := 10;
  r
)

devolverá una función que añade 10 a su argumento, en lugar de 5. Esto es porque el diccionario adicional se crea sólo cuando el contexto en el que la función se define termina, que es cuando la función f devuelve su valor. Esto es consistente con cómo que esperaría que la función r actuara dentro de la función f según las reglas sobre el ámbito de variables en GEL. Al diccionario adicional sólo se añaden las variables que se utilizaron en contextos que recién terminan y que ya no existen. Las variables que se utilizan en la función que están en contextos que se mantienen válidos funcionan de manera usual, utilizan el valor actual de la variable. La única diferencia es entre las variables globales y las funciones. Todos los identificadores que hacen referencia a variables globales al momento de definir la función no se agregan al diccionario privado. Esto es para evitar trabajo innecesario al devolver una función y rara vez será un problema. Por ejemplo, suponga que borra «k=5» de la función f y que, en el nivel más alto, define k como 5, por ejemplo. Cuado ejecute la función f, la función r no añadirá k al diccionario privado pues ésta es una variable global (del nivel más alto) en el momento en que se definió r.

Algunas veces es mejor tener más control sobre cómo las variables se copian al diccionario privado. Desde la versión 1.0.7 puede especificar qué variables se copian al diccionario privado colocando corchetes adicionales después de los argumentos con la lista de variables que se desean copiar separadas con comas. Si hace esto, las variables se copiarán al diccionario privado en el momento que se define la función, y no se tocará el diccionario privado después de esto. Por ejemplo,

function f() = (
  k := 5;
  function r(x) [k] = (x+k);
  k := 10;
  r
)

devuelve una función que cuando se llama añade 5 a su argumento. La copia local de k se crea cuando la función se define.

Cuando quiera que la función no tenga un diccionario privado escriba un par de corchetes vacíos después de la lista de argumentos. Con esto no se creará ningún diccionario privado. Hacer esto es útil para incrementar la eficiencia cuando no se necesita un diccionario privado o cuando quiere que la función busque todas las variables cuando las ve al momento que se la llama. Por ejemplo, suponga que quiere que la función que devuelve f ve el valor de k del nivel más alto sin importar que hay una variable con el mismo nombre al momento de la definición. El código

function f() = (
  k := 5;
  function r(x) [] = (x+k);
  r
);
k := 10;
g = f();
g(10)

devuelve 20 y no 15, lo que podría suceder si se hubiese añadido k con valor 5 al diccionario privado.