tgoop.com/bear_the_software_engineer/978
Last Update:
چیشد و چرا یهو lambda calculus رو به Closure ربط داد؟
از جایی شروع کنیم که هنوز خبری از Closure نبود؛ روزهایی که برنامهنویسان با زبانهایی مثل Algol 60 تازه با مفهوم توابع تو در تو آشنا میشدند. در آن دوران، گروهی از پژوهشگران در نشست ۱۹۵۸ زوریخ قواعد «block structure» را برای ALGOL 60 تصویب کردند و واژههایی مثل begin … end
را وارد ادبیات کدنویسی کردند. همین تصمیم ساده نقطهٔ آغاز چیزی شد که بعدها lexical scope نام گرفت: قانونی که میگوید دامنهٔ یک نام/متغیر دقیقاً همان جایی است که در متن برنامه نوشته شده، نه جای دیگری در زمان اجرا.
واژهٔ «lexical» نخستینبار حوالی ۱۹۶۷ در گزارشهای Cambridge ظاهر شد؛ کریستوفر استراچی با الهام از ریشهٔ یونانی lexis تأکید کرد که دامنهٔ متغیر، خصیصهٔ خودِ source code است، نه call stack. چنین نگرشی روشن میکرد که اگر تابع inner داخل تابع outer تعریف شود، بدون هیچ جستوجویی در زمان اجرا به متغیرهای outer دسترسی خواهد داشت. در قطعهٔ زیر، inner حتی بعد از تمام شدن outer همچنان مقدار count را میبیند، زیرا ساختار نوشتاری برنامه آن را در بر گرفته است:
function outer() {
let count = 0;
function inner() {
console.log(count);
}
return inner;
}
outer() // 0
این رفتارِ بهظاهر جادویی اما در عمل به جایی میرسید که دیگر call stack پاسخگو نبود؛ پس از برگشت مقدار از
outer
، متغیرهای محلی عملاً از حافظهٔ فعال حذف میشدند. درست همینجاست که Peter J. Landin وارد داستان میشود. او برای حفظ آن «private state» ماشینی انتزاعی به نام SECD machine طراحی کرد. ایدهاش ساده بود: هر تابع را همراه با محیط متغیرهایی که در لحظهٔ تعریف در دسترسش بودند بستهبندی کن و این بسته را Closure بنام. از آن پس، توابع میتوانستند مثل کولهپشتی، مقادیر بیرونی را با خود حمل کنند حتی وقتی از محدودهٔ اصلی خارج میشدند. عمل دسترسی داشتن به متغیر ها توسط lexical scope تعیین میشد ولی این Closure بود که تضمین میکرد که متغیر های محلی حتما باقی بمانند.
اما Landin این ایده را از کجا آورد؟ پاسخ در lambda calculus نهفته است؛ همان زبان نمادینی که Alonzo Church برای مدلسازی «محاسبه» ابداع کرد. در lambda calculus نوشتن
λx. f(x, y)
یعنی تعریف تابعی بدون نام که یک پارامتر دارد (x). این x را bound variable مینامیم چون داخل همان abstraction تعریف و مقداردهی میشود. در برابر آن،
y
یک free variable است؛ در بدنهٔ تابع ظاهر شده اما پارامتر نیست و باید از محیط بیرونی گرفته شود. معنی Closure دقیقاً «بستن» این free variableهاست: هنگام ساخت تابع، مقدار آنها ذخیره میشود تا تابع در هر زمان دیگری اجرا شد، هنوز به همان مقدار دست یابد.حالا ممکنه بگید که آقا زبان ریاضی رو ول کن یه کد به ما نشون بده! معادل نوشته بالا میشه کد پایین
const g = x => f(x, y);
ولی بزارید یکم باز ترش کنم
// یک مقدار خارجی برای y
const y = 5;
// تعریف تابع f که دو آرگومان x و y میگیرد
const f = (x, y) => {
// در این مثال f فقط جمع میزند؛
return x + y;
};
// معادل عبارت λx. f(x, y)
const g = x => f(x, y);
console.log(g(3)); // خروجی: 8 (چون 3 + 5)
BY خرسِ برنامه نویس
Share with your friend now:
tgoop.com/bear_the_software_engineer/978