سؤال

هل يمكن لأحد أن يشرح؟أنا أفهم المفاهيم الأساسية وراءها ولكني غالبًا ما أراها تستخدم بالتبادل وأشعر بالارتباك.

والآن بما أننا هنا، كيف تختلف عن الدالة العادية؟

هل كانت مفيدة؟

المحلول

أ لامدا هي مجرد وظيفة مجهولة - وظيفة محددة بدون اسم.في بعض اللغات، مثل Scheme، تكون مكافئة للوظائف المسماة.في الواقع، يتم إعادة كتابة تعريف الدالة على أنه ربط لامدا بمتغير داخليًا.في لغات أخرى، مثل بايثون، هناك بعض الفروق (غير الضرورية إلى حد ما) بينهما، لكنها تتصرف بنفس الطريقة بخلاف ذلك.

أ إنهاء هي أي وظيفة التي يغلق ال بيئة التي تم تعريفها فيها.وهذا يعني أنه يمكنه الوصول إلى المتغيرات غير الموجودة في قائمة المعلمات الخاصة به.أمثلة:

def func(): return h
def anotherfunc(h):
   return func()

سيؤدي هذا إلى حدوث خطأ، لأن func لا إغلاق أكثر البيئة في anotherfunc - h غير محدد. func يغلق فقط على البيئة العالمية.هذا سيفي بالغرض:

def anotherfunc(h):
    def func(): return h
    return func()

لأنه هنا، func تم تعريفه في anotherfunc, ، وفي بيثون 2.3 وأكبر (أو رقم مثل هذا) عندما بالكاد حصلت على عمليات الإغلاق الصحيحة (ما زالت الطفرة لا تعمل)، وهذا يعني أنها كذلك يغلق anotherfuncبيئة ويمكن الوصول إلى المتغيرات داخلها.في Python 3.1+، تعمل الطفرة أيضًا عند الاستخدام ال nonlocal الكلمة الرئيسية.

نقطة أخرى مهمة - func سوف تستمر في الإغلاق anotherfuncبيئة حتى عندما لم يعد يتم تقييمها فيها anotherfunc.سيعمل هذا الكود أيضًا:

def anotherfunc(h):
    def func(): return h
    return func

print anotherfunc(10)()

سيتم طباعة 10.

وهذا، كما لاحظت، لا علاقة له به لامداs - هما مفهومان مختلفان (رغم أنهما مرتبطان).

نصائح أخرى

هناك الكثير من الالتباس حول عمليات الإغلاق واللامدا، حتى في الإجابات على سؤال StackOverflow هنا.بدلاً من سؤال المبرمجين العشوائيين الذين تعلموا عن عمليات الإغلاق من خلال التدريب على لغات برمجة معينة أو غيرهم من المبرمجين الجاهلين، قم برحلة إلى مصدر (حيث بدأ كل شيء).وبما أن لامدا والإغلاقات تأتي من حساب التفاضل والتكامل لامدا اخترعها ألونزو تشيرش في الثلاثينيات قبل ظهور أول أجهزة الكمبيوتر الإلكترونية، هذا هو مصدر أنا أتكلم عن.

Lambda Calculus هي أبسط لغة برمجة في العالم.الأشياء الوحيدة التي يمكنك القيام بها فيه:►

  • طلب:يُشار إلى تطبيق تعبير على آخر f x.
    (فكر في الأمر على أنه استدعاء وظيفة, ، أين f هي وظيفة و x هي المعلمة الوحيدة)
  • التجريد:يربط رمزًا يحدث في تعبير للإشارة إلى أن هذا الرمز هو مجرد "فتحة"، أو مربع فارغ ينتظر أن يتم ملؤه بقيمة، أو "متغير" كما كان.ويتم ذلك عن طريق إضافة حرف يوناني مسبقًا λ (لامدا)، ثم الاسم الرمزي (مثلا: x)، ثم نقطة . قبل التعبير.يؤدي هذا بعد ذلك إلى تحويل التعبير إلى a وظيفة أتوقع واحدة معامل.
    على سبيل المثال: λx.x+2 يأخذ التعبير x+2 ويحكي أن الرمز x في هذا التعبير هو متغير منضم - يمكن استبدالها بقيمة تقدمها كمعلمة.
    لاحظ أن الوظيفة المحددة بهذه الطريقة هي مجهول – ليس له اسم، لذلك لا يمكنك الرجوع إليه بعد، ولكن يمكنك ذلك اتصل على الفور (هل تتذكر التطبيق؟) عن طريق تزويده بالمعامل الذي ينتظره، مثل هذا: (λx.x+2) 7.ثم التعبير (في هذه الحالة قيمة حرفية) 7 يتم استبداله كما x في التعبير الفرعي x+2 من لامدا المطبقة، حتى تحصل 7+2, ، والذي يقلل بعد ذلك إلى 9 من خلال القواعد الحسابية المشتركة.

لذلك قمنا بحل أحد الألغاز:
لامدا هل وظيفة مجهولة من المثال أعلاه، λx.x+2.


في لغات البرمجة المختلفة، قد يختلف بناء جملة التجريد الوظيفي (لامدا).على سبيل المثال، في JavaScript يبدو الأمر كما يلي:

function(x) { return x+2; }

ويمكنك تطبيقه على الفور على بعض المعلمات مثل هذا:

(function(x) { return x+2; })(7)

أو يمكنك تخزين هذه الوظيفة المجهولة (lambda) في بعض المتغيرات:

var f = function(x) { return x+2; }

مما يعطيها اسمًا بشكل فعال f, ، مما يسمح لك بالرجوع إليه واستدعاءه عدة مرات لاحقًا، على سبيل المثال:

alert(  f(7) + f(10)  );   // should print 21 in the message box

لكن لم يكن عليك تسميتها.يمكنك تسميتها على الفور:

alert(  function(x) { return x+2; } (7)  );  // should print 9 in the message box

في LISP، يتم تصنيع لامدا على النحو التالي:

(lambda (x) (+ x 2))

ويمكنك استدعاء مثل هذا lambda من خلال تطبيقه فورًا على المعلمة:

(  (lambda (x) (+ x 2))  7  )


حسنًا، حان وقت حل اللغز الآخر:ما هو إنهاء.من أجل القيام بذلك، دعونا نتحدث عن حرف او رمز (المتغيرات) في تعبيرات لامدا.

كما قلت، ما يفعله تجريد لامدا هو ربط رمز في تعبيره الفرعي، بحيث يصبح بديلاً معامل.يسمى هذا الرمز مرتبط ب.ولكن ماذا لو كان هناك رموز أخرى في التعبير؟على سبيل المثال: λx.x/y+2.في هذا التعبير الرمز x لا بد من تجريد لامدا λx. يسبقه.ولكن الرمز الآخر y, ، ليست ملزمة - بل هو حر.نحن لا نعرف ما هو ومن أين يأتي، لذلك لا نعرف ما هو وسائل و ماذا قيمة إنه يمثل، وبالتالي لا يمكننا تقييم هذا التعبير حتى نكتشف ماهيته y وسائل.

في الواقع، الشيء نفسه ينطبق على الرمزين الآخرين، 2 و +.كل ما في الأمر أننا على دراية بهذين الرمزين لدرجة أننا عادة ننسى أن الكمبيوتر لا يعرفهما وعلينا أن نخبره بما يعنيه من خلال تعريفهما في مكان ما، على سبيل المثال.في المكتبة أو اللغة نفسها.

يمكنك التفكير في حر الرموز كما تم تعريفها في مكان آخر، خارج التعبير، في "السياق المحيط به"، والذي يسمى به بيئة.قد تكون البيئة تعبيرًا أكبر يكون هذا التعبير جزءًا منه (كما قال Qui-Gon Jinn:"هناك دائمًا سمكة أكبر" ;))، أو في بعض المكتبات، أو في اللغة نفسها (مثل بدائية).

يتيح لنا هذا تقسيم تعبيرات لامدا إلى فئتين:

  • التعبيرات المغلقة:كل رمز يحدث في هذه التعبيرات هو مرتبط ب بواسطة بعض التجريد لامدا.وبعبارة أخرى، هم مكتفية ذاتيا;أنها لا تتطلب تقييم أي سياق محيط.ويطلق عليهم أيضا المجمعات.
  • التعبيرات المفتوحة:بعض الرموز في هذه التعبيرات ليست كذلك مرتبط ب - أي أن بعض الرموز التي تحدث فيها هي حر وهي تتطلب بعض المعلومات الخارجية، وبالتالي لا يمكن تقييمها حتى تقوم بتزويد تعريفات هذه الرموز.

يمكنك إغلاق يفتح تعبير لامدا عن طريق توفير بيئة, ، والذي يحدد كل هذه الرموز المجانية من خلال ربطها ببعض القيم (والتي قد تكون أرقامًا أو سلاسل أو وظائف مجهولة تُعرف أيضًا باسم lambdas أو أيًا كان ...).

وهنا يأتي إنهاء جزء:
ال إنهاء من أ تعبير لامدا هي هذه المجموعة المحددة من الرموز المحددة في السياق الخارجي (البيئة) التي تعطي قيمًا للكائن رموز مجانية في هذا التعبير، مما يجعلها غير حرة بعد الآن.يتحول ا يفتح تعبير لامدا، الذي لا يزال يحتوي على بعض الرموز الحرة "غير المحددة"، في ملف مغلق واحد، والذي لم يعد يحتوي على أي رموز مجانية.

على سبيل المثال، إذا كان لديك تعبير لامدا التالي: λx.x/y+2, ، الرمز x لا بد، في حين أن الرمز y فهو حر، وبالتالي فإن التعبير هو open ولا يمكن تقييمها إلا إذا قلت ماذا y يعني (ونفس الشيء مع + و 2, ، وهي مجانية أيضًا).ولكن لنفترض أن لديك أيضًا بيئة مثله:

{  y: 3,
+: [built-in addition],
2: [built-in number],
q: 42,
w: 5  }

هذا بيئة يوفر تعريفات لجميع الرموز "غير المحددة" (المجانية) من تعبير لامدا الخاص بنا (y, +, 2)، والعديد من الرموز الإضافية (q, w).الرموز التي نحتاج إلى تعريفها هي هذه المجموعة الفرعية من البيئة:

{  y: 3,
+: [built-in addition],
2: [built-in number]  }

وهذا هو بالضبط إنهاء من تعبير لامدا لدينا :>

وبعبارة أخرى، فإنه يغلق تعبير لامدا مفتوح.هذا هو المكان الاسم إنهاء جاء في المقام الأول، ولهذا السبب فإن إجابات الكثير من الأشخاص في هذا الموضوع ليست صحيحة تمامًا:P


فلماذا هم مخطئون؟لماذا يقول الكثير منهم أن عمليات الإغلاق هي بعض هياكل البيانات في الذاكرة، أو بعض ميزات اللغات التي يستخدمونها، أو لماذا يخلطون بين عمليات الإغلاق واللامدا؟:ص

حسنًا، الشركات السوقية مثل Sun/Oracle وMicrosoft وGoogle وما إلى ذلك.هم المسؤولون، لأن هذا هو ما أطلقوا عليه هذه التركيبات في لغاتهم (Java، C#، Go وما إلى ذلك).غالبًا ما يطلقون على "الإغلاقات" ما يفترض أن يكون مجرد لامدا.أو يسمون "الإغلاقات" وهي تقنية معينة استخدموها لتنفيذ النطاق المعجمي، أي حقيقة أن الوظيفة يمكنها الوصول إلى المتغيرات التي تم تعريفها في نطاقها الخارجي في وقت تعريفها.غالبًا ما يقولون أن الوظيفة "تحتوي" على هذه المتغيرات، أي أنها تلتقطها في بعض هياكل البيانات لحمايتها من التدمير بعد انتهاء تنفيذ الوظيفة الخارجية.ولكن هذا مجرد مكياج بعد فوات الأوان "أصل الكلمة الفولكلورية" والتسويق، مما يجعل الأمور أكثر إرباكًا، لأن كل بائع لغة يستخدم مصطلحاته الخاصة.

والأمر أسوأ من ذلك لأن هناك دائمًا القليل من الحقيقة فيما يقولونه، وهو ما لا يسمح لك بسهولة استبعاده باعتباره خطأ: P دعني أشرح:

إذا كنت ترغب في تنفيذ لغة تستخدم لامدا كمواطنين من الدرجة الأولى، فأنت بحاجة إلى السماح لهم باستخدام الرموز المحددة في السياق المحيط بهم (أي استخدام المتغيرات الحرة في لامدا الخاصة بك).ويجب أن تكون هذه الرموز موجودة حتى عند عودة الدالة المحيطة.تكمن المشكلة في أن هذه الرموز مرتبطة ببعض وحدات التخزين المحلية للوظيفة (عادةً في مكدس الاستدعاءات)، والتي لن تكون موجودة بعد الآن عندما تعود الوظيفة.لذلك، لكي تعمل لامدا بالطريقة التي تتوقعها، تحتاج إلى "التقاط" كل هذه المتغيرات الحرة بطريقة ما من سياقها الخارجي وحفظها لوقت لاحق، حتى عندما يختفي السياق الخارجي.وهذا هو، تحتاج إلى العثور على إنهاء من lambda الخاص بك (كل هذه المتغيرات الخارجية التي يستخدمها) وتخزينها في مكان آخر (إما عن طريق عمل نسخة، أو عن طريق إعداد مساحة لها مقدمًا، في مكان آخر غير المكدس).الطريقة الفعلية التي تستخدمها لتحقيق هذا الهدف هي "تفاصيل التنفيذ" للغتك.المهم هنا هو إنهاء, ، وهي مجموعة من المتغيرات الحرة من بيئة من لامدا الخاص بك والتي تحتاج إلى حفظها في مكان ما.

لم يستغرق الأمر وقتًا طويلاً حتى يبدأ الأشخاص في استدعاء بنية البيانات الفعلية التي يستخدمونها في تطبيقات لغتهم لتنفيذ الإغلاق باعتباره "الإغلاق" نفسه.يبدو الهيكل عادةً كما يلي:

Closure {
   [pointer to the lambda function's machine code],
   [pointer to the lambda function's environment]
}

ويتم تمرير هياكل البيانات هذه كمعلمات إلى وظائف أخرى، ويتم إرجاعها من الوظائف وتخزينها في متغيرات لتمثيل لامدا، والسماح لها بالوصول إلى البيئة المحيطة بها بالإضافة إلى كود الآلة للتشغيل في هذا السياق.لكنها مجرد طريقة (واحدة من عدة طرق). ينفذ إغلاق، لا ال الإغلاق نفسه.

كما أوضحت أعلاه، فإن إغلاق تعبير لامدا هو مجموعة فرعية من التعريفات في بيئته التي تعطي قيمًا للمتغيرات الحرة الموجودة في تعبير لامدا هذا، بشكل فعال إغلاق التعبير (تحويل يفتح تعبير لامدا، الذي لا يمكن تقييمه بعد، إلى ملف مغلق تعبير لامدا، والذي يمكن بعد ذلك تقييمه، حيث تم الآن تعريف جميع الرموز الموجودة فيه).

أي شيء آخر هو مجرد "عبادة البضائع" و"سحر الفودو" للمبرمجين وبائعي اللغات غير المدركين للجذور الحقيقية لهذه المفاهيم.

أرجو أن تجيب على الأسئلة الخاصة بك.ولكن إذا كانت لديك أية أسئلة أخرى، فلا تتردد في طرحها في التعليقات، وسأحاول شرحها بشكل أفضل.

وعندما يفكر معظم الناس من وظائف ، يفكرون في <قوية> وظائف اسمه : ل

function foo() { return "This string is returned from the 'foo' function"; }
تسمى

وهذه بالاسم، بالطبع:

foo(); //returns the string above

مع تعبيرات لامدا ، هل يمكن أن يكون على وظائف مجهولة : ل

 @foo = lambda() {return "This is returned from a function without a name";}

ومع المثال أعلاه، يمكنك استدعاء امدا من خلال متغير تم تعيينه إلى:

foo();

وأكثر فائدة من تعيين وظائف مجهولة إلى المتغيرات، ومع ذلك، يتم تمريرها إلى أو من وظائف النظام العالي، أي الوظائف التي تقبل / تعود وظائف أخرى. في الكثير من هذه الحالات، تسمية وظيفة هو لا لزوم لها:

function filter(list, predicate) 
 { @filteredList = [];
   for-each (@x in list) if (predicate(x)) filteredList.add(x);
   return filteredList;
 }

//filter for even numbers
filter([0,1,2,3,4,5,6], lambda(x) {return (x mod 2 == 0)}); 

A <م> إغلاق قد يكون اسمه أو وظيفة غير معروفة ولكن كما هو معروف مثل عندما "يغلق فوق" المتغيرات في نطاق حيث يتم تعريف وظيفة، أي إغلاق سوف لا تزال تشير إلى البيئة مع أية متغيرات الخارجية التي يتم استخدامها في إغلاق نفسها. وفيما يلي إغلاق اسمه:

@x = 0;

function incrementX() { x = x + 1;}

incrementX(); // x now equals 1

وهذا لا يبدو مثل الكثير ولكن ماذا لو كان كل هذا في وظيفة أخرى، والذي تم تمريره incrementX إلى وظيفة الخارجية؟

function foo()
 { @x = 0;

   function incrementX() 
    { x = x + 1;
      return x;
    }

   return incrementX;
 }

@y = foo(); // y = closure of incrementX over foo.x
y(); //returns 1 (y.x == 0 + 1)
y(); //returns 2 (y.x == 1 + 1)

وهذه هي الطريقة التي تحصل الأشياء جليل في البرمجة الوظيفية. منذ تسمية "incrementX" ليست هناك حاجة، يمكنك استخدام امدا في هذه الحالة:

function foo()
 { @x = 0;

   return lambda() 
           { x = x + 1;
             return x;
           };
 }

وليس كل الاغلاق lambdas وليس كل lambdas والإغلاق. كلاهما وظائف، ولكن ليس بالضرورة بالطريقة التي اعتدنا على معرفة.

وA امدا هي في الأساس وظيفة التي تم تعريفها مضمنة بدلا من الطريقة القياسية إعلان الوظائف. ويمكن في كثير من الأحيان Lambdas يتم تداولهما ككائنات.

والإغلاق هو وظيفة أن يرفق الدولة المحيطة بها عن طريق الرجوع الحقول الخارجية لجسمها. تبقى الدولة المغلقة عبر الدعاء الإغلاق.

في لغة وجوه المنحى، وتقدم عادة من خلال إغلاق الكائنات. ومع ذلك، بعض اللغات OO (على سبيل المثال C #) تنفيذ الوظائف الخاصة التي هي أقرب إلى تعريف الإغلاق التي تقدمها بحتة اللغات الوظيفية (مثل ثغة) التي لا تحتوي على كائنات لإحاطة الدولة.

ما هو المثير للاهتمام هو أن إدخال Lambdas والإغلاق في C # يجلب البرمجة الوظيفية أقرب إلى استخدام التيار.

وانها بسيطة مثل هذا: امدا هو بناء اللغة، أي ببساطة بناء الجملة من أجل وظائف مجهولة. إغلاق هو أسلوب لتنفيذ ذلك - أو أية وظائف من الدرجة الأولى، لهذه المسألة، واسمه أو مجهول

وبشكل أكثر تحديدا، والإغلاق هو كيف يتم تمثيل وظيفة من الدرجة الأولى في وقت التشغيل ، وزوج من "ميثاق" والبيئة "إغلاق" على كل المتغيرات غير المحلية المستخدمة في ذلك الرمز. بهذه الطريقة، هذه المتغيرات لا تزال متاحة حتى عندما تم خرجت نطاقات الخارجية حيث تنشأ بالفعل.

ولسوء الحظ، هناك العديد من اللغات من هناك التي لا تدعم وظائف كقيم من الدرجة الأولى، أو فقط تقديم الدعم لهم في شكل بالشلل. من الناس في كثير من الأحيان استخدام مصطلح "إغلاق" للتمييز "الشيء الحقيقي".

من وجهة نظر لغات البرمجة، فهي تماما هما شيئان مختلفان.

وأساسا للغة كاملة تورينج نحن بحاجة فقط عناصر محدودة جدا، على سبيل المثال التجريد، وتطبيق والحد منها. التجريد والتطبيق يوفر الطريقة التي يمكن أن تتراكم lamdba التعبير، والحد من dertermines معنى التعبير امدا.

وامدا يوفر وسيلة يمكنك مجردة عملية حسابية بها. على سبيل المثال، لحساب مجموع عددين، وهي عملية تأخذ معلمتين X، Y والعوائد س + ص يمكن أن تستخرج بها. في المخطط، يمكنك عمل ذلك بكتابة

(lambda (x y) (+ x y))

ويمكنك إعادة تسمية المعلمات، ولكن المهمة التي تعمل على إتمام لا يتغير. في معظم لغات البرمجة، يمكنك إعطاء التعبير امدا اسما، والتي تتم تسمية الوظائف. ولكن ليس هناك فرق كبير، ويمكن اعتبار المفهوم كما السكر في بناء الجملة عادل.

وOK، تخيل الآن كيف يمكن تنفيذها. كلما طبقنا التعبير امدا لبعض التعبيرات، منها مثلا.

((lambda (x y) (+ x y)) 2 3)

ويمكننا ببساطة استبدال المعلمات مع التعبير التي يتم تقييمها. هذا النموذج هو بالفعل قوية جدا. ولكن هذا النموذج لا تمكننا من تغيير القيم من الرموز، على سبيل المثال، ونحن لا يمكن أن تحاكي تغيير الوضع. وبالتالي نحن في حاجة إلى نموذج أكثر تعقيدا. لجعلها قصيرة، كلما أردنا لحساب معنى التعبير امدا، وضعنا الزوج من الرمز والقيمة المقابلة في بيئة (أو الجدول). ثم يتم تقييم بقية (+ س ص) عن طريق البحث عن الرموز المقابلة في الجدول. الآن إذا وفرنا بعض الأوليات للعمل على بيئة مباشرة، يمكننا أن نموذج للتغيير وضعهم!

ومع هذه الخلفية، والتحقق من هذه الوظيفة:

(lambda (x y) (+ x y z))

ونحن نعلم أنه عندما نقيم التعبير امدا، سوف تكون ملزمة X Y في جدول جديد. ولكن كيف وأين يمكن أن ننظر ض يصل؟ في الواقع يسمى ض متغير مجانا. يجب أن تكون هناك صلة خارجية بيئة الذي يحتوي ض. وإلا فإن معنى التعبير لا يمكن تحديده من خلال x و y ملزمة فقط. لجعل هذا واضح، يمكن أن تكتب شيئا على النحو التالي في مخطط:

((lambda (z) (lambda (x y) (+ x y z))) 1)

وهكذا ض أن تكون ملزمة ل1 في جدول الخارجي. ونحن لا تزال تحصل على وظيفة التي تقبل معلمتين ولكن المعنى الحقيقي لأنه يعتمد أيضا على البيئة الخارجية. وبعبارة أخرى تغلق البيئة الخارجية على المتغيرات الحرة. مع مساعدة من مجموعة !، يمكننا أن نجعل وظيفة جليل، أي بمعنى، انها ليست وظيفة بالمعنى المقصود في الرياضيات. ما يعود ليس فقط يعتمد على المدخلات، ولكن ض كذلك.

وهذا شيء كنت تعرف جيدا للغاية، وسيلة لكائنات تعتمد دائما تقريبا على الدولة من الكائنات. لهذا السبب يقول بعض الناس "الإغلاق هي كائنات الرجل الفقير". ولكن يمكننا أيضا النظر في الأشياء كما الإغلاق الرجل الفقير لأننا حقا مثل وظائف الدرجة الأولى.

وأنا استخدم مخطط لتوضيح الأفكار نظرا لهذا المخطط هي واحدة من أقدم اللغات التي لديها إغلاق الحقيقية. وكثيرا عرض جميع المواد هنا أفضل في SICP الفصل 3.

لتلخيص، امدا وإغلاق مفاهيم مختلفة حقا. A امدا هي وظيفة. A الإغلاق هو زوج لامدا والبيئة المقابلة التي تغلق امدا.

ومفهوم هو نفسه كما هو موضح أعلاه، ولكن إذا كنت من PHP الخلفية، وهذا يفسر زيادة استخدام كود PHP.

$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, function ($v) { return $v > 2; });

وظيفة ($ ت) {عودة $ الخامس> 2. } هو تعريف الدالة امدا. نحن حتى يمكن تخزينه في متغير، لذلك يمكن أن تكون قابلة لإعادة الاستخدام:

$max = function ($v) { return $v > 2; };

$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max);

والآن، ما إذا كنت ترغب في تغيير الحد الأقصى المسموح به في مجموعة تصفيتها؟ سيكون لديك لكتابة وظيفة امدا آخر أو إنشاء إغلاق (PHP 5.3):

$max_comp = function ($max) {
  return function ($v) use ($max) { return $v > $max; };
};

$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max_comp(2));

والإغلاق هو دالة التي يتم تقييمها في بيئته الخاصة، التي لديها واحد أو أكثر المربوطة المتغيرات التي يمكن الوصول إليها عندما يتم استدعاء الدالة. انهم يأتون من العالم برمجة وظيفية، حيث هناك عدد من المفاهيم في اللعب. الاغلاق مثل وظائف لامدا، ولكن أكثر ذكاء، بمعنى أن لديهم القدرة على التفاعل مع المتغيرات من البيئة الخارجية من حيث يتم تعريف الإغلاق.

وهنا مثال أبسط PHP الإغلاق:

$string = "Hello World!";
$closure = function() use ($string) { echo $string; };

$closure();

أوضح لطيف في هذه المقالة.

وهذه مسألة قديمة وحصلت على العديد من الإجابات. الآن مع جافا 8 و امدا الرسمية أن هناك مشاريع الإغلاق غير رسمية أنها تحيي هذه المسألة.

والجواب في سياق جافا (عبر Lambdas والإغلاق - ما هي الفرق ):؟

<اقتباس فقرة>   

و"A الإغلاق هو تعبير لامدا يقترن بيئة التي تربط كل متغيراته مجانية إلى القيمة. في جاوة، وسيتم تنفيذ عبارات امدا عن طريق إغلاق، لذلك حان المصطلحين لاستخدامها بالتبادل في المجتمع ".

وتحدث ببساطة، وإغلاق هو خدعة حول نطاق، امدا هي وظيفة غير معروفة. يمكننا أن ندرك مع إغلاق امدا أكثر أناقة وامدا كثيرا ما يستخدم كمعلمة تمريرها إلى وظيفة أعلى

وتعبير لامبدا هو مجرد وظيفة غير معروفة. في جافا عادي، على سبيل المثال، يمكنك كتابة مثل هذا:

Function<Person, Job> mapPersonToJob = new Function<Person, Job>() {
    public Job apply(Person person) {
        Job job = new Job(person.getPersonId(), person.getJobDescription());
        return job;
    }
};

وحيث هو وظيفة من الدرجة بنيت فقط في كود جافا. الآن يمكنك الاتصال mapPersonToJob.apply(person) مكان لاستخدامها. أن يكون مثالا واحدا فقط. أن يكون لامدا قبل ذلك كان هناك بناء الجملة من أجل ذلك. Lambdas طريقا مختصرا لهذا الغرض.

وإغلاق:

ولامدا يصبح الإغلاق عندما يمكن الوصول إلى المتغيرات خارج هذا النطاق. اعتقد انك يمكن القول سحره، فإنه سحرية يمكن أن يلتف حول البيئة تم إنشاؤه في واستخدام المتغيرات خارج نطاقه (نطاق الخارجي. ذلك أن تكون واضحة، وإغلاق يعني امدا يمكن الوصول إلى نطاقه الخارجي.

وفي Kotlin، يمكن لامدا الوصول دائما إغلاقها (المتغيرات التي هي في نطاق الخارجي لها)

يعتمد ذلك على ما إذا كانت الوظيفة تستخدم متغيرًا خارجيًا أم لا لإجراء العملية.

المتغيرات الخارجية - المتغيرات المحددة خارج نطاق الوظيفة.

  • تعبيرات لامدا هي عديمي الجنسية لأنه يعتمد على المعلمات أو المتغيرات الداخلية أو الثوابت لتنفيذ العمليات.

    Function<Integer,Integer> lambda = t -> {
        int n = 2
        return t * n 
    }
    
  • الإغلاق عقد الدولة لأنه يستخدم متغيرات خارجية (أي.متغير محدد خارج نطاق نص الوظيفة) مع المعلمات والثوابت لتنفيذ العمليات.

    int n = 2
    
    Function<Integer,Integer> closure = t -> {
        return t * n 
    }
    

عندما تقوم Java بإنشاء الإغلاق، فإنها تحتفظ بالمتغير n مع الوظيفة حتى يمكن الرجوع إليه عند تمريره إلى وظائف أخرى أو استخدامه في أي مكان.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top