HotXLS מעריך LAMBDA של Excel כערך פונקציה ממדרגה ראשונה אמיתי. שם מוגדר שהטקסט של RefersTo שלו הוא LAMBDA אפשר לקרוא לו בשם כ-=MyFunc(5), סגירה שקשורה בתוך LET אפשר לקרוא לה כ-=LET(f, LAMBDA(x, x*2), f(21)), והסביבה הלקסיקלית שנלכדה בזמן ההגדרה נוסעת יחד עם הסגירה. טקסט הנוסחה עובר הלוך-חזור אל תוך חוברת העבודה מילה במילה
זו התכונה שמפרידה מנוע נוסחאות ממנתח נוסחאות. כל מה שקדם ל-LAMBDA היה אפשר להעריך בהליכה על עץ ערכים. LAMBDA דורש מחסנית תחום, וברגע שיש מחסנית תחום, מחלקה שלמה של לוגיקת גיליון אלקטרוני שכתב משתמש מתחילה לעבוד ביישום ה-Delphi שלכם במקום רק ב-Excel
מדוע רוב המנועים שאינם Excel נעצרים במילה LAMBDA?
מפני שלמעריך גיליון אלקטרוני קלאסי יש בדיוק סוג ערך אחד: מספר, מחרוזת, בוליאני, שגיאה, או הפניה לתאים שמחזיקים אותם. אין איפה לשים פונקציה. כש-Excel 365 הציג את LAMBDA, הוא הוסיף סוג ערך שנושא שמות פרמטרים, ביטוי גוף, והקשרים הנראים במקום שבו הוא נכתב. מנוע ללא הסוג הזה יכול לנתח LAMBDA(x, x*2) ולאחסן את הטקסט, אבל ברגע שתא מנסה לקרוא לו, אין מה לקרוא
HotXLS מממש את החלק החסר כערך סגירה בתוספת מחסנית תחום בזמן ריצה. קריאה לסגירה דוחפת את הסביבה שנלכדה, ואז דוחפת את ערכי הארגומנטים תחת שמות הפרמטרים, מעריכה את הגוף, וחותכת את המחסנית בחזרה לסימון. הסדר הזה חשוב, והסעיף הבא מסביר למה
שלוש הדרכים שבהן LAMBDA נקרא
HotXLS פותר קריאה לשם פונקציה לא ידוע דרך שלושה נתיבים, בסדר הזה, וידיעה איזה מהם מופעל מסבירה את רוב ההפתעות. ראשית, שם קשור בתחום LET או LAMBDA הנוכחי: אם f הוא קישור מקומי שמחזיק סגירה, f(21) מחיל אותה. שנית, שם מוגדר בחוברת העבודה שטקסט הנוסחה שלו מתחיל ב-LAMBDA: MyFunc(5) מקמפל את גוף השם הזה ומחיל אותו. שלישית, מטפל הפונקציה המוגדרת-משתמש הקלאסי, ללא שינוי, לכל מה ששני הנתיבים הראשונים לא תובעים
קישור מקומי שמחזיק משהו שאינו סגירה אינו ניתן לקריאה. קשרו את f למספר 3 ואז כתבו f(21) ותקבלו שגיאת ערך, לא ניסיון כפל. זה מחמיר יותר ממה ששפה דינמית הייתה, ובכוונה: טעות כתיב שהופכת קריאה לפונקציה להפניה מקרית היא תשובה שגויה שקטה, וזו התוצאה הגרועה ביותר שמנוע גיליון אלקטרוני יכול להפיק
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
begin
Book := TXLSXWorkbook.Create;
try
Sheet := Book.Sheets.Add('Model');
// פונקציה שמית לשימוש חוזר, בתחום חוברת העבודה
Book.DefinedNames.Add('NetOf', 'LAMBDA(amount, rate, amount*(1-rate))');
Sheet.Cells[2, 2].Formula := 'NetOf(1250, 0.19)';
// סגירה שנקשרת ומוחלת בתוך נוסחה אחת
Sheet.Cells[3, 2].Formula := 'LET(double, LAMBDA(x, x*2), double(21))';
// LET מקונן: כל קישור נראה לאלה שאחריו
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;
איך הצללה נפתרת כששמות מתנגשים?
פרמטרים מנצחים. כש-HotXLS מחיל סגירה הוא דוחף קודם את הסביבה הלקסיקלית שנלכדה ואת קשרי הארגומנטים שני, כך שפרמטר בשם rate מצל קישור חיצוני בשם rate וגם מצל הפניית עמודה בעלת אותה כתיב בנוסחה הסובבת. הסדר הזה הוא מה שהופך פונקציה שמית לבטוחה לשימוש חוזר: הקורא לא יכול לשנות בטעות את משמעות הגוף על ידי החזקת קישור בעל שם דומה בתחום
ה-arity נבדק לפני שכל דבר מוערך. קריאה שמספר הארגומנטים שלה לא תואם את מספר הפרמטרים של הסגירה מחזירה שגיאת ערך מיידית, במקום להעריך כמה ארגומנטים ואז להיכשל, מה ששומר על הערכה חסרת תופעות-לוואי חופשיה באמת מעבודה חלקית. מחסנית התחום נחתכת בחזרה לסימון הכניסה שלה בבלוק finally, כך ששגיאה בתוך גוף לא יכולה להשאיר קישורים ישנים גלויים לנוסחה הבאה
var
Book: TXLSXWorkbook;
Name: TXLSXDefinedName;
begin
Book := TXLSXWorkbook.Create;
try
if Book.Open('customer-model.xlsx') = 1 then
begin
// בדקו מה המשתמש כתב לפני שסומכים על חישוב מחדש
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 כבר לא חלקי
גרסאות קודמות של HotXLS מימשו LET רק עד כדי לטפל במקרה הנפוץ של קישור בודד. המימוש הנוכחי שלם: כל קישור נראה לכל הקישורים המאוחרים ולביטוי הגוף, ו-LET מקונן מרכיב באופן רגיל, כך ש-LET(a, 1, b, a+1, LET(c, b*2, c)) מוערך בדיוק כפי ש-Excel מעריך אותו
השלמות הזו חשובה יותר ממה שהיא נשמעת. LET הוא האופן שבו משתמשים נמנעים מחישוב חוזר של אותו תת-ביטוי חמש פעמים בנוסחה אחת, כך שחוברות עבודה אמיתיות משתמשות בו בדיוק בצורות המקוננות עמוק שמימוש חלקי טועה בהן. אם קודם עקפתם פערים בהרחבת קישורי LET לפני ההערכה, אפשר לוותר על העקיפה הזו
פסיק או נקודה-פסיק: שניהם עכשיו
טקסט נוסחה ב-HotXLS מקבל כעת פסיק כמפריד ארגומנטים לצד נקודה-פסיק הקלאסית. זו אינה הגדרת אזור; זהו כלל קבלה במנתח. זה חשוב מפני שנוסחאות מגיעות ממקומות שאין לכם שליטה עליהם: מודבקות מכרטיס תמיכה, מועתקות מתוך תיעוד, מיוצרות על ידי סקריפט שפלט את התחביר הקנוני של Excel, מיובאות מקובץ CSV של מחרוזות נוסחה
ההשפעה המעשית היא ש-SUM(A1,A2) ו-SUM(A1;A2) שניהם מתקמפלים. הלוך-חזור שומר על מה שהמקור השתמש בו, כך שחוברת עבודה שנטענה נכתבת בחזרה עם המפרידים המקוריים שלה במקום להיות מנורמלת מאחורי גבו של המשתמש
מה עובר הלוך-חזור, ומה לבדוק
טקסט הנוסחה מאוחסן מילה במילה, כך ש-LAMBDA בשם מוגדר שורד מחזור טעינה ושמירה שלם ונפתח ב-Excel כאותה פונקציה. LAMBDA חשוף המאוחסן כתוצאת תא, כלומר נוסחה שמתפתחת לסגירה במקום לערך, שומר על התנהגות הדילוג-ללא-ערך הקיימת: הטקסט נשמר, לא מומצאת תוצאה מספרית שמורה עבורו. זו התוצאה הכנה, מפני שאין סקלר לשמור
שני הרגלים שווים אימוץ. תנו ללמבדות שמיות תחום חוברת עבודה אלא אם יש סיבה שלא, מפני שפונקציה בתחום גיליון שנעלמת כשגיליון מועתק מפיקה שגיאת שם במקום רחוק מהסיבה; כללי התחום מכוסים בשמות מוגדרים ונוסחאות חוצות-גיליון. וכשחוברת עבודה מלאה בלמבדות שמיות מיועדת לדוח שחייב להיות יציב, שקלו להקפיא את התוצאות עם ConvertFormulasToValues כך שצרכנים בהמשך יראו מספרים ולא פונקציות שהם אולי לא תומכים בהן
לחישוב מחדש כבד, גופי LAMBDA הם ביטויים רגילים בגרף התלות ומתוזמנים כמו כל נוסחה אחרת, וזה מתואר בחישוב מחדש מצטבר וגרף התלות. אם המודל שלכם קורא לאותה פונקציה שמית על פני אלפי שורות, העלות היא הגוף, לא מנגנון הקריאה, וחלה אותה עצת אופטימיזציה כמו לכל נוסחה חוזרת
HotXLS הוא רכיב גיליון אלקטרוני מקורי ל-Delphi ול-C++Builder שקורא וכותב XLS, XLSX ו-ODS ללא Excel וללא כל אוטומציית Office. מנוע הנוסחאות, השמות המוגדרים וה-API של חישוב מחדש מתועדים בדף רכיב HotXLS ל-Delphi