Teknik Makale

HotXLS: Delphi ile LAMBDA, LET ve Formül Kapanışları

HotXLS, Excel LAMBDA'yı gerçek bir birinci sınıf fonksiyon değeri olarak değerlendirir. RefersTo metni bir LAMBDA olan tanımlı bir ad, =MyFunc(5) olarak adıyla çağrılabilir; LET içinde bağlanmış bir kapanış =LET(f, LAMBDA(x, x*2), f(21)) olarak çağrılabilir ve tanımlandığı anda yakalanan sözcüksel ortam kapanışla birlikte seyahat eder. Formül metni çalışma kitabına birebir geri yazılır

Bir formül motorunu bir formül ayrıştırıcısından ayıran özellik budur. LAMBDA'dan öncesindeki her şey bir değer ağacını dolaşarak değerlendirilebilirdi. LAMBDA bir kapsam yığını gerektirir ve bir kapsam yığınınız olduğunda, kullanıcının yazdığı elektronik tablo mantığının koca bir sınıfı yalnızca Excel'de değil Delphi uygulamanızda da çalışmaya başlar

Excel dışındaki çoğu motor neden LAMBDA anahtar sözcüğünde durur?

Çünkü klasik bir elektronik tablo değerlendiricisinin tam olarak tek bir değer türü vardır: bir sayı, bir dize, bir mantıksal değer, bir hata ya da bunları taşıyan hücrelere bir başvuru. Bir fonksiyonu koyacak bir yer yoktur. Excel 365, LAMBDA'yı tanıttığında, parametre adlarını, bir gövde ifadesini ve yazıldığı yerde görünür olan bağlamaları taşıyan bir değer türü ekledi. Bu türe sahip olmayan bir motor LAMBDA(x, x*2)'yi ayrıştırıp metnini saklayabilir, ama bir hücre onu çağırmaya kalktığı anda çağıracak hiçbir şey yoktur

HotXLS eksik parçayı bir kapanış değeri artı bir çalışma zamanı kapsam yığını olarak uygular. Bir kapanışı çağırmak, önce yakalanan ortamını yığına iter, sonra parametre adları altında argüman değerlerini iter, gövdeyi değerlendirir ve yığını işarete geri kırpar. Bu sıra önemlidir ve bir sonraki bölüm nedenini açıklar

Bir LAMBDA çağrılmanın üç yolu

HotXLS, bilinmeyen bir fonksiyon adına yönelik bir çağrıyı sırayla denenen üç yoldan çözer ve hangisinin ateşlendiğini bilmek çoğu sürprizi açıklar. Birincisi, geçerli LET veya LAMBDA kapsamında bağlanmış bir ad: f yerel bir bağlamaysa ve bir kapanış tutuyorsa, f(21) onu uygular. İkincisi, formül metni LAMBDA ile başlayan bir çalışma kitabı tanımlı adı: MyFunc(5) o adın gövdesini derler ve uygular. Üçüncüsü, klasik kullanıcı fonksiyonu işleyicisidir, değişmeden, ilk ikisinin talep etmediği her şey için

Bir kapanıştan başka bir şey tutan yerel bir bağlama çağrılabilir değildir. f'yi 3 sayısına bağlayın ve sonra f(21) yazın; çarpma girişimi değil bir değer hatası alırsınız. Bu, dinamik bir dilin olacağından daha katıdır ve bilinçli olarak öyledir: bir fonksiyon çağrısını yanlışlıkla bir başvuruya çeviren bir yazım hatası, sessiz bir yanlış cevaptır ki bu, bir elektronik tablo motorunun üretebileceği en kötü sonuçtur

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
begin
  Book := TXLSXWorkbook.Create;
  try
    Sheet := Book.Sheets.Add('Model');

    // Yeniden kullanılabilir adlı bir fonksiyon, çalışma kitabı kapsamı
    Book.DefinedNames.Add('NetOf', 'LAMBDA(amount, rate, amount*(1-rate))');

    Sheet.Cells[2, 2].Formula := 'NetOf(1250, 0.19)';

    // Tek bir formül içinde bağlanan ve uygulanan bir kapanış
    Sheet.Cells[3, 2].Formula := 'LET(double, LAMBDA(x, x*2), double(21))';

    // İç içe LET: her bağlama kendisinden sonrakilere görünür
    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;

Adlar çakıştığında gölgeleme nasıl çözülür?

Parametreler kazanır. HotXLS bir kapanışı uyguladığında önce yakalanan sözcüksel ortamı, sonra argüman bağlamalarını iter; bu yüzden rate adlı bir parametre, dışarıdaki rate adlı bir bağlamayı gölgeler ve çevredeki formülde aynı yazımlı bir sütun başvurusunu da gölgeler. Bu sıralama, adlı bir fonksiyonu yeniden kullanmayı güvenli kılan şeydir: çağıran kişi, kapsamda benzer adlı bir bağlamaya sahip olarak gövdenin anlamını yanlışlıkla değiştiremez

Argüman sayısı, hiçbir şey değerlendirilmeden önce kontrol edilir. Argüman sayısı kapanışın parametre sayısıyla eşleşmeyen bir çağrı, bazı argümanları değerlendirip sonra başarısız olmak yerine anında bir değer hatası döndürür; bu, yan etkisiz değerlendirmeyi gerçekten kısmi işten arındırılmış tutar. Kapsam yığını, bir finally bloğunda giriş işaretine geri kırpılır; bu yüzden bir gövdenin içindeki bir hata, eski bağlamaları bir sonraki formüle görünür bırakamaz

var
  Book: TXLSXWorkbook;
  Name: TXLSXDefinedName;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.Open('customer-model.xlsx') = 1 then
    begin
      // Bir yeniden hesaplamaya güvenmeden önce kullanıcının ne yazdığını incele
      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 artık kısmi değil

Önceki HotXLS sürümleri LET'i yalnızca yaygın tek bağlamalı durumu karşılayacak kadar uyguladı. Mevcut uygulama tamdır: her bağlama tüm sonraki bağlamalara ve gövde ifadesine görünürdür ve iç içe LET normal şekilde birleşir; bu yüzden LET(a, 1, b, a+1, LET(c, b*2, c)), Excel'in değerlendirdiği şekilde değerlendirilir

Bu tamlık kulağa geldiğinden daha önemlidir. LET, kullanıcıların bir formülde aynı alt ifadeyi beş kez yeniden hesaplamaktan kaçınma yoludur; bu yüzden gerçek çalışma kitapları onu tam olarak kısmi bir uygulamanın yanlış yaptığı derin iç içe geçmiş biçimlerde kullanır. Değerlendirmeden önce LET bağlamalarını genişleterek boşlukları daha önce aşıyorsanız, o geçici çözümden artık vazgeçebilirsiniz

Virgül mü noktalı virgül mü: artık ikisi de

HotXLS'teki formül metni, artık klasik noktalı virgülün yanında virgülü de argüman ayırıcı olarak kabul ediyor. Bu bir yerel ayar değil, ayrıştırıcıdaki bir kabul kuralıdır. Önemlidir çünkü formüller kontrol etmediğiniz yerlerden gelir: bir destek talebinden yapıştırılmış, belgelerden kopyalanmış, Excel'in kanonik söz dizimini yayan bir betikten üretilmiş, formül dizelerinden oluşan bir CSV'den içe aktarılmış

Pratik etki, SUM(A1,A2) ve SUM(A1;A2)'nin ikisinin de derlenmesidir. Geri yazma, kaynağın kullandığı ne ise onu korur; bu yüzden yüklediğiniz bir çalışma kitabı, kullanıcının arkasından normalleştirilmek yerine orijinal ayırıcılarıyla geri yazılır

Ne geri yazılır ve ne kontrol edilmeli

Formül metni birebir saklanır; bu yüzden tanımlı bir addaki bir LAMBDA, bir yükleme ve kaydetme döngüsünden sağlam çıkar ve Excel'de aynı fonksiyon olarak açılır. Bir hücre sonucu olarak saklanan çıplak bir LAMBDA, yani bir değere değil bir kapanışa değerlenen bir formül, mevcut değersiz-atlama davranışını korur: metin saklanır, onun için hiçbir önbelleğe alınmış sayısal sonuç uydurulmaz. Bu, dürüst sonuçtur, çünkü önbelleğe alınacak bir sayısal değer yoktur

Edinilmeye değer iki alışkanlık var. Bir nedeniniz olmadıkça adlı lambdalara çalışma kitabı kapsamı verin, çünkü bir sayfa kopyalandığında kaybolan sayfa kapsamlı bir fonksiyon, nedeninden çok uzak bir yerde bir ad hatası üretir; kapsam kuralları tanımlı adlar ve sayfa arası formüllerde ele alınmıştır. Ve adlı lambdalarla dolu bir çalışma kitabı kararlı olması gereken bir rapor için hazırlanıyorsa, alt akıştaki tüketicilerin desteklemeyebileceği fonksiyonlar yerine sayılar görmesi için sonuçları ConvertFormulasToValues ile dondurmayı düşünün

Ağır yeniden hesaplama için, LAMBDA gövdeleri bağımlılık grafiğinde sıradan ifadelerdir ve diğer her formül gibi zamanlanır; bu, artımlı yeniden hesaplama ve bağımlılık grafiğinde anlatılmıştır. Modeliniz binlerce satır boyunca adlı bir fonksiyonu çağırıyorsa, maliyet çağrı mekanizması değil gövdedir ve aynı optimizasyon tavsiyesi tekrarlanan herhangi bir formül için geçerlidir

HotXLS, Excel ya da herhangi bir Office otomasyonu olmadan XLS, XLSX ve ODS okuyup yazan yerel bir Delphi ve C++Builder elektronik tablo bileşenidir. Formül motoru, tanımlı adlar ve yeniden hesaplama API'si HotXLS Delphi elektronik tablo bileşeni sayfasında belgelenmiştir