Vracení funkcí

Existuje možnost, jak vracet funkce jako hodnoty. Tímto způsobem můžete vytvářet funkce, které konstruují funkce pro speciální účely podle určitých parametrů. Trochu trik je, jak udělat proměnné, aby je funkce viděla. Způsob, který funguje v jazyce GEL je, že když funkce vrací jinou funkci, tak všechny identifikátory odkazované v těle funkce, které jdou mimo rozsah působnosti, mají předřazen privátní slovník vracené funkce. Takže funkce bude vidět všechny proměnné, které byly v rozsahu působnosti, když byla definována. Například nadefinujeme funkci, která vrací funkci, která přičítá 5 ke svému argumentu.

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

Všimněte si, že funkce přičítá k k x. Použili byste ji následovně:

g = f();
g(5)

A g(5) by mělo vrátit 10.

Jedna věc, kterou je potřeba si uvědomit, je, že hodnota k, která je použita, je ve skutečnosti ta ve chvíli, kdy se vrací funkce f. Například

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

bude vracet funkci, která ke svému argumentu přičítá 10 a ne 5. To proto, že je vytvořen dodatečný slovník, jen když kontext, ve kterém končí definice funkce, je ten jako když se funkce f vrací. Což je konzistentní s tím, jak byste očekávali, že bude funkce r pracovat uvnitř funkce f podle pravidel o rozsahu působnosti proměnných v jazyce GEL. Do dodatečného slovníku jsou přidány jen ty proměnné, které jsou v kontextu, který právě končí a nadále již neexistuje. Proměnné použité ve funkci, které jsou ve stále platném kontextu, budou pracovat obvykle s použitím aktuální hodnoty proměnné. Jediný rozdíl je v globálních proměnných a funkcích. Všechny identifikátory, které odkazovaly na globální proměnné ve chvíli, kdy definice funkce není přidána do privátního slovníku. To je kvůli tomu, aby se zabránilo nepotřebné práci, když se vrací funkce a zřídka by byly problémem. Například předpokládejme, že vymažete z funkce f výraz „n=5“ a v nejvyšší úrovni definujete k, které bude řekněme 5. Když pak spustíte funkci f, funkce r nebude proměnnou k vkládat do privátního slovníku, protože je v době definice r globální (v nejvyšší úrovni).

Někdy je lepší mít větší kontrolu na tím, jak jsou proměnné kopírovány do privátního slovníku. Od verze 1.0.7 můžete určovat, které proměnné jsou kopírovány do privátního slovníku tak, že za argumenty vložíte dodatečné hranaté závorky se seznamem proměnných oddělených čárkou, které se mají kopírovat. Pokud tak učiníte, proměnné jsou zkopírovány do privátního slovníku v okamžiku definice funkce a dodatečně se již slovník nemění. Například

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

bude vracet funkci, která při zavolání přičte 5 ke svému argumentu. Lokální kopie k byla vytvořena ve chvíli, kdy byla funkce definována.

Když chcete, aby funkce neměla žádný privátní slovník, tak vložte za seznam argumentů prázdné hranaté závorky. V takovém případě nebude vytvořen vůbec žádný privátní slovník. To je dobré pro zvýšení efektivity v situacích, kdy žádný privátní slovník není zapotřebí nebo když chcete, aby funkce hledala všechny proměnné takové, jaké jsou v okamžiku volání. Například předpokládejme že chcete, aby funkce vracená funkcí f viděla hodnotu n z nejvyšší úrovně, přestože existuje lokální proměnná stejného jména během definování. Potom kód

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

bude vrace 20 a ne 15, což by nastalo v případě, že n s hodnotou 5 bylo přidáno do privátního slovníku.