HotXLS evaluira Excel LAMBDA kao pravu vrijednost funkcije prve klase. Definirano ime čiji je tekst RefersTo LAMBDA može se pozvati po imenu kao =MyFunc(5), closure vezan unutar LET-a može se pozvati kao =LET(f, LAMBDA(x, x*2), f(21)), a leksičko okruženje zahvaćeno u trenutku definicije putuje zajedno s closureom. Tekst formule vraća se u radnu knjigu doslovno, nepromijenjen
Ovo je značajka koja razdvaja mehanizam za formule od običnog parsera formula. Sve prije LAMBDA-e moglo se evaluirati prolaskom kroz stablo vrijednosti. LAMBDA zahtijeva stog opsega, a čim imate stog opsega, cijela klasa korisnički napisane logike proračunskih tablica počinje raditi u vašoj Delphi aplikaciji, a ne samo u Excelu
Zašto većina mehanizama koji nisu Excel stane kod ključne riječi LAMBDA?
Zato što klasični evaluator proračunske tablice ima točno jednu vrstu vrijednosti: broj, niz znakova, boolean, pogrešku ili referencu na ćelije koje sadrže te vrijednosti. Nema mjesta gdje bi se smjestila funkcija. Kada je Excel 365 uveo LAMBDA-u, dodao je tip vrijednosti koji nosi imena parametara, izraz tijela i vezanja vidljiva na mjestu gdje je napisana. Mehanizam bez tog tipa može parsirati LAMBDA(x, x*2) i pohraniti tekst, ali u trenutku kada ćelija pokuša tu funkciju pozvati, nema što pozvati
HotXLS implementira taj nedostajući dio kao vrijednost closurea plus stog opsega tijekom izvođenja. Pozivanje closurea gura na stog njegovo zahvaćeno okruženje, zatim gura vrijednosti argumenata pod imenima parametara, evaluira tijelo i skraćuje stog natrag na oznaku. Taj redoslijed ima značenje, a sljedeći odjeljak objašnjava zašto
Tri načina na koja se LAMBDA poziva
HotXLS razrješava poziv nepoznatom imenu funkcije kroz tri putanje, isprobane redom, a znanje koja se od njih aktivira objašnjava većinu iznenađenja. Prvo, ime vezano u trenutnom LET ili LAMBDA opsegu: ako je f lokalno vezanje koje sadrži closure, f(21) ga primjenjuje. Drugo, definirano ime radne knjige čiji tekst formule počinje s LAMBDA: MyFunc(5) kompajlira tijelo tog imena i primjenjuje ga. Treće, klasični rukovatelj korisničkim funkcijama, nepromijenjen, za sve što prve dvije putanje ne pokriju
Lokalno vezanje koje sadrži nešto drugo osim closurea nije pozivljivo. Vežite f uz broj 3, a zatim napišite f(21) i dobit ćete pogrešku vrijednosti, a ne pokušaj množenja. Ovo je strože nego što bi bio dinamički jezik, i to namjerno: pravopisna pogreška koja poziv funkcije pretvori u slučajnu referencu tihi je pogrešan odgovor, a to je najgori mogući ishod koji mehanizam proračunske tablice može proizvesti
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
begin
Book := TXLSXWorkbook.Create;
try
Sheet := Book.Sheets.Add('Model');
// Funkcija za višekratnu upotrebu, opseg radne knjige
Book.DefinedNames.Add('NetOf', 'LAMBDA(amount, rate, amount*(1-rate))');
Sheet.Cells[2, 2].Formula := 'NetOf(1250, 0.19)';
// Closure vezan i primijenjen unutar jedne formule
Sheet.Cells[3, 2].Formula := 'LET(double, LAMBDA(x, x*2), double(21))';
// Ugniježđeni LET: svako je vezanje vidljivo onima koji slijede
Sheet.Cells[4, 2].Formula :=
'LET(base, 100, bump, LAMBDA(v, v+base), LET(step, bump(5), step*2))';
Book.Recalculate;
Book.SaveAs('lambda-model.xlsx');
finally
Book.Free;
end;
end;
Kako se razrješava zasjenjivanje kada se imena sudare?
Parametri pobjeđuju. Kada HotXLS primjenjuje closure, prvo gura zahvaćeno leksičko okruženje, a zatim vezanja argumenata, pa parametar imenom rate zasjenjuje vanjsko vezanje istog imena rate, a zasjenjuje i istoimenu referencu na stupac u okolnoj formuli. Taj redoslijed čini imenovanu funkciju sigurnom za ponovnu upotrebu: pozivatelj ne može slučajno promijeniti značenje tijela funkcije time što u opsegu ima slično imenovano vezanje
Aritet se provjerava prije nego što se bilo što evaluira. Poziv čiji se broj argumenata ne podudara s brojem parametara closurea odmah vraća pogrešku vrijednosti, umjesto da evaluira neke argumente i tek onda ne uspije, čime evaluacija bez nuspojava ostaje istinski bez djelomično obavljenog posla. Stog opsega skraćuje se natrag na oznaku ulaska unutar bloka finally, tako da pogreška unutar tijela ne može ostaviti zastarjela vezanja vidljivima sljedećoj formuli
var
Book: TXLSXWorkbook;
Name: TXLSXDefinedName;
begin
Book := TXLSXWorkbook.Create;
try
if Book.Open('customer-model.xlsx') = 1 then
begin
// Pregledajte ono što je korisnik napisao prije nego što povjerujete ponovnom izračunu
Name := Book.DefinedNames.FindByName('NetOf');
if (Name <> nil) and
(UpperCase(Copy(Name.Formula, 1, 6)) = 'LAMBDA') then
Log('Named lambda found: ' + Name.Formula);
Book.Recalculate;
Log(VarToStr(Book.Sheets[1].Cells[2, 2].Value));
end;
finally
Book.Free;
end;
end;
LET više nije djelomičan
Ranija izdanja HotXLS-a implementirala su LET samo dovoljno da pokriju uobičajen slučaj s jednim vezanjem. Trenutna je implementacija potpuna: svako je vezanje vidljivo svim kasnijim vezanjima i izrazu tijela, a ugniježđeni LET-ovi se normalno sastavljaju, pa se LET(a, 1, b, a+1, LET(c, b*2, c)) evaluira jednako kao što ga evaluira Excel
Ta potpunost znači više nego što zvuči. LET je način na koji korisnici izbjegavaju ponovno izračunavanje istog podizraza pet puta unutar jedne formule, pa ga stvarne radne knjige koriste upravo u onim duboko ugniježđenim oblicima koje djelomična implementacija pogrešno obradi. Ako ste ranije zaobilazili te nedostatke tako da ste razvijali LET vezanja prije evaluacije, to zaobilaženje sada možete ukloniti
Zarez ili točka-zarez: sada oboje
Tekst formule u HotXLS-u sada prihvaća zarez kao razdjelnik argumenata uz klasičnu točku-zarez. To nije postavka lokalizacije; to je pravilo prihvaćanja u parseru. Ima značenje jer formule stižu s mjesta koja ne kontrolirate: zalijepljene iz prijave podrške, kopirane iz dokumentacije, generirane skriptom koja je emitirala Excelovu kanonsku sintaksu, uvezene iz CSV-a nizova formula
Praktičan je učinak da se i SUM(A1,A2) i SUM(A1;A2) podjednako kompajliraju. Kružni ciklus čuva ono što je izvor koristio, pa se radna knjiga koju ste učitali zapisuje natrag s izvornim razdjelnicima, umjesto da se normalizira iza korisnikovih leđa
Što se čuva kroz kružni ciklus, i što provjeriti
Tekst formule pohranjuje se doslovno, pa LAMBDA u definiranom imenu preživi ciklus učitavanja i spremanja netaknuta i otvara se u Excelu kao ista funkcija. Gola LAMBDA pohranjena kao rezultat ćelije, odnosno formula koja se evaluira u closure umjesto u vrijednost, zadržava postojeće ponašanje preskoči-bez-vrijednosti: tekst se čuva, a za nju se ne izmišlja predmemorirani brojčani rezultat. To je iskren ishod, budući da nema skalara koji bi se predmemorirao
Vrijedi usvojiti dvije navike. Dajte imenovanim lambdama opseg radne knjige osim ako postoji razlog da to ne učinite, jer funkcija s opsegom lista koja nestane kada se list kopira proizvodi pogrešku imena na mjestu daleko od uzroka; pravila opsega obrađena su u članku definirana imena i formule preko više listova. A kada je radna knjiga puna imenovanih lambdi namijenjena izvještaju koji mora biti stabilan, razmotrite zamrzavanje rezultata pomoću ConvertFormulasToValues, tako da potrošači nizvodno vide brojeve umjesto funkcija koje možda ne podržavaju
Kod intenzivnog ponovnog izračuna, tijela LAMBDA-e obični su izrazi u grafu ovisnosti i raspoređuju se kao i svaka druga formula, što je opisano u članku inkrementalni ponovni izračun i graf ovisnosti. Ako vaš model poziva jednu imenovanu funkciju kroz tisuće redaka, trošak je tijelo funkcije, a ne mehanizam poziva, a vrijede iste smjernice za optimizaciju kao i za bilo koju ponovljenu formulu
HotXLS je izvorna Delphi i C++Builder komponenta za proračunske tablice koja čita i piše XLS, XLSX i ODS bez Excela ili bilo kakve automatizacije Officea. API za mehanizam formula, definirana imena i ponovni izračun dokumentiran je na stranici HotXLS Delphi komponente za proračunske tablice