تثمين كسول
في نظرية لغة البرمجة، إنَّ التثمين الكسول  أو الاستدعاء عند الحاجة ، هي استراتيجية تثمين تؤخِّر تثمين التعبير لحين احتياج قيمته (تثمين غير صارم) وَتتجنّب بذلك -مُشاركة- التَثمينات المُتكرِّرة. يُمكن للمُشاركة إنقاص وقت تشغيل دوال مُعيَّنة بعاملٍ أُسِّي على استراتيجيَّات التثمين غير الصارم، مثل الاستدعاء بالاسم.

تتضمَّن منافع التثمين الكسول:
 القدرة على تعريف بُنى تدفق السيطرة بتجريدٍ بدلًا من أن تكون مُدمجة.
 القدرة على تعريف بُنى بيانات مُمكنة الأزليَّة، يسمح هذا بتنفيذ دقيق للمزيد من الخوارزميَّات.
 زيادة الأداء بتجنُّب الحسابات غير الضروريَّة وَالأخطاء في حالة تثمين التعابير المُركَّبة.

غالبًا ما يُدمَج التثمين الكسول مع استحضار الذاكرة(memoization أو memoisation)، كما قد ذُكِر في «كتابة برامج كفء»(Writing Efficient Programs) لِـجون بينتلي، غالبًا ما يُدمَج التثمين الكسول مع التذكُّر. بعد أن تُحوسب قيمة الدالَّة من أجل مُعطىً أو مجموعة من المُعطيات، فإنَّ النَّتيجة تُخَزَّن في جدول المُشاهدات المُفَهرَس وفق قيم المُعطيات؛ وفي المرَّة القادمة الَّتي سَتُستَدعى فيها الدالَّة سيتم تفقُّد الجدول لتحديد فيما إذا كانت نتيجة قيم المُعطيات متوفِّرةً بالفعل أم لا. عندها وببساطة سَتُعاد قيمة النتيجة المُخَزَّنة وَإن كان العكس فَسيتم تثمين الدالَّة وَيُضاف مُدخَل جديد إلى جدول المُشاهدات لِيُعاد استخدامه لاحقًا.

قد يؤدِّي التثمين الكسول إلى نقص في الذكرة اللّازمة للبرامج(المحجوزة لها)؛ لأنَّ القيم تُنسَئ عند الحاجة إليها. ومن الصَّعب دمج التثمين الكسول مع المَزايا الأمريَّة مثل استيعاب الأخطاء وَالدخل/الخرج، لأنّ ترتيب العمليّات يصبح غيرَ مُحدَّدٍ. وَقد يسبّب التثمين الكسول تسرب الذاكرة.

عكس التثمين الكسول هو «التثمين اللَّهوف»(eager evaluation)؛ وَأحيانًا يُعرَف باسم التثمين الصارم(strict evaluation). ولقد وظِّف التثمين اللَّهوف كاستراتيجيّة تثمين في أغلب لُغات البرمجة.

لمحة تاريخيّة 
قُدِّمَ التثمين الكسول من أجل حسابات اللامدا من قِبَل كريستوفر وادز-ورث وَباستقلالٍ من أجل لُغات البرمجة من قِبَل بيتر هيندرسن وَجيمس حيرم موريس وَدانيال بول فريدمان وَديفيد س. وايز.

التطبيقات 
يُستخدم التثمين المؤجَّل(Delayed evaluation) تحديدًا في لُغات البرمجة الوظيفيَّة. فعند استخدام التثمين المؤجَّل، لا يتم تثمين التعبير عند إسناده إلى مُتَغَيِّر بل يُثَمَّن عند الحاجة لإنتاج قيمة التعبير. هذه إفادة كمثال، x:=expression; (إسناد نتيجة التعبير إلى مُتَغَيِّر). بوضوحٍ، تَمَّ استدعاء التعبير بُغية تثمينه وَوُضِعَت النتيجة في x، لكن يتم تعليق ما بداخل x لِحين احتياج قيمته وذلك باستخدام فهرس يقود إلى x في تعبيرٍ ما لاحِقٍ وقد يكون هذا التعبير أيضًا مؤجّلًا، وأخيرًا تُشَذَّب شجرة الاعتماديَّات النامية هذه لإنتاج بعض الرموز الّتي يُفَضَّل رؤيتها.

من فوائد التثمين المؤجَّل قدرته على إنشاء قوائم لانهائيَّة قابلة للحِساب بدون تداخل الحلقات اللَّانهائيَّة أو الحجم في الحِساب. كمثال، يُمكن إنشاء دالَّة تُنشِئ قائمة لانهائيَّة (تُدعى غالبًا «جريان») من أعداد فيبوناتشي. إنَّ حِساب عدد فيبوناتشيّ ما -وليكن «ن»- سيكون بكلّ بساطة استخلاصًا لهذا العنصر -الّذي هو العدد «ن»- من القائمة اللَّانهائيَّة، مُجبرًا بذلك على تثمين أوَّل ن عنصر من القائمة.

كمثال، يُمكن في لغة البرمجة هاسكل كتابة قائمة بكلّ أعداد فيبوناتشي كالتالي:

 fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

في نحويَّة هاسكل، «:» تُضيف عنصرًا إلى بداية القائمة وَ«tail» تعود بالقائمة بدون عنصرها الأوَّل وَ«zipWith» تَستَخدِم دالَّة مُعَيَّنة (في حالتنا هذه هي الجمع «+») لجمع العناصر المُتوافقة لِكلا القائمتين بهدف إنتاج قائمة ثالثة.

يجب أن يكون المبرمج حذرًا وَدقيقًا؛ لأنّه يتم فقط تثمين القيم اللّازمة لإنتاج نتيجة معيّنة. ومع ذلك، قد تؤدّي بعض الحسابات إلى محاولة البرنامج لتثمين عدد لا حصر له من العناصر؛ على سبيل المثال، طلب طول القائمة أو محاولة جمع عناصر القائمة بعملية الطيّ  يؤدي بالبرنامج إمَّا إلى فشل الإنهاء أو نفاد الذاكرة.

بُنى التحكّم 
في كلّ اللّغات «اللّهوفة» تقريبًا، يتمّ تثمين الإفادة «if» بأسلوب كسولٍ.
 if a then b else c
سيتمّ تثمين (a)، وَإذا وَفقط إذا ثُمِّنَت (a) لتكون صح «true» سيتمّ تثمين (b) وَإلّا سيتمّ تثمين (c). وبذلك لن يتمّ تثمين واحد من (b) وَ (c). بالمُقابِل، سيكون السلوك المُتَوَقَّع هو هذا:
 define f(x, y) = 2 * x
 set k = f(d, e)
سيتمّ تثمين (e) عند حِساب قيمة f(d, e) وعلى الرُّغم من ذلك فقيمة (e) غير مُستخدمة في الدالَّة f. وبالتالي تعتمد بُنى التحكّم المُعرَّفة من قِبَل المُستَخدِم على النحويَّة المضبوطة، كمثال:
 define g(a, b, c) = if a then b else c
 l = g(h, i, j)
سيتمّ تثمين كُلٍّ من (i) وَ (j) في اللُّغة اللَّهوفة. بينما في اللُّغة الكسولة،
 l' = if h then i else j
سيتمّ تثمين إمَّا (i) أو (j)، ولن يتمّ تثمين كليهما معًا أبدًا.

يسمَح التثمين الكسول بتعريف بُنى التحكّم طبيعيًّا، وَلكن لا يسمح لها أن تكون مُدمَجة أو كتقنيّات وقت-التجميع. فإذا كان لِـ (i) أو (j) آثارًا جانبيّةً أو أثارت أخطاءً في وقت التشغيل، عنها ستكون الاختلافات غير الملحوظة بين (l) وَ (l') مُعَقَّدَةً. وَمن المُمكن عادةً إنشاء بُنى تحكّمٍ كسولة يُعرّفها المُستخدِم كَدوالٍّ في اللُّغات اللَّهوفة، لذلك قد تُزاح تلك الدَّوال من نحويَّة اللُّغة عند التثمين اللَّهوف: غالبًا ما يُحتَاج ادّثار جسد الشِفرة (مثل: (i) وَ (j)) ليصبح قيمة الدالَّة، ولذلك يتمّ فقط تنفيذها عند الاستدعاء.

يُدعى التثمين قصير الدوران (وَيُسمّى أيضًا: تثمين دُونيّ أو تثمين مَكارثي) لِبُنى التحكّم البوليانيّة(المنطقيّة) تثمينًا «كسولًا».

العمل مع بُنى بيانات أزليّة 
توفّر العديد من اللُّغات مفهوم «بُنى-البيانات الأزليّة (لا محدودة)» . ويسمح ذلك بتعريف البيانات كمجالات أزليّة أو كتعاوديّة غير منتهية (unending recursion)، لكن يتمّ حساب القيم الفعليّة عندما نحتاجها فحسب. تفقّد هذا المِثال المتواضع؛ وهو برنامج في لغة هاسكل:

numberFromInfiniteList :: Int -> Int
numberFromInfiniteList n = infinity !! n - 1
    where infinity = [1..]

main = print $ numberFromInfiniteList 4

في الدالَّة numberFromInfiniteList، إنّ قيمة infinity هي مجال لا محدود، ولحين احتياجه يتمّ تثمين المجال وصولًا إلى المؤشِّر (index) المطلوب.

قائمة الأنماط الناجحة

المراجع

مصادر

قراءة موسَّعة 
  PhD thesis, Oxford University
 
 
 
 أنماط التصميم
 John Hughes. "Why functional programming matters". مجلة الحاسوب - Special issue on lazy functional programming. Volume 32 Issue 2, April 1989.
 Philip Wadler. "How to replace failure by a list of successes a method for exception handling, backtracking, and pattern matching in lazy functional languages". Functional Programming Languages and Computer Architecture. Lecture Notes in Computer Science, 1985, Volume 201/1985, 113-128.
 الكسل في اللُّغات الصَّارمة
 Philip Wadler, Walid Taha, and David MacQueen. "How to add laziness to a strict language, without even being odd". Workshop on Standard ML, Baltimore, September 1998.
 تدوينات لعلماء الحاسوب
 . "The Point of Laziness"
 Lennart Augustsson. "More points for lazy evaluation"

روابط خارجيّة 
 Lazy Evaluation at the Portland Pattern Repository
 Lazy evaluation at Haskell Wiki
 The Incomplete Guide to Lazy Evaluation (in Haskell) – A series of tutorials on lazy evaluation in Haskell: How it works, how it helps making code more modular, and other things.
 Functional programming in Python becomes lazy
 Lazy function argument evaluation in the D language
 Lazy evaluation macros in Nemerle
 Lambda calculus in Boost Libraries in C++ language
 Lazy Evaluation in Perl

تحقيق أمثلية المجمع
إستراتيجية تثمين
تنفيذ للغات البرمجة الوظيفية
في نظرية لغة البرمجة ، إنَّ التثمين الكسول أو ال استدعاء عند الحاجة ، هي استراتيجية تثمين تؤخِّر تثمين التعبير ل حين احتياج قيمة ه ( تثمين غير صارم ) وَت تجنب ب ذٰلك - مُشاركة - التَثمينات المُتكرِّرة . يُمكن للمُشاركة إنقاص وقت تشغيل دوال مُعيَّنة بعاملٍ أُسِّي على استراتيجيَّات التثمين غير الصارم ، مثل ال استدعاء بالاسم . تتضمَّن منافع التثمين الكسول : القدرة على تعريف بُنى تدفق السيطرة بتجريدٍ بدلًا من أن تكون مُدمجة . القدرة على تعريف بُنى بيانات مُمكنة الأزليَّة ، يسمح هذا ب تنفيذ دقيق للمزيد من الخوارزميَّات . زيادة الأداء بتجنُّب الحسابات غير الضروريَّة وَالأخطاء في حالة تثمين التعابير المُركَّبة . غالبًا ما يُدمَج التثمين الكسول مع استحضار الذاكرة ( memoization أو memoisation ) ، كما قد ذُكِر في « كتابة برامج كفء » ( Writing Efficient Progra m s ) لِـجون بينتلي ، غالبًا ما يُدمَج التثمين الكسول مع التذكُّر . بعد أن تُحوسب قيمة الدالَّة من أجل مُعطىً أو مجموعة من المُعطيات ، فإنَّ النَّتيجة تُخَزَّن في جدول المُشاهدات المُفَهرَس وفق قيم المُعطيات ؛ و في المرَّة القادمة الَّتي سَتُستَدعى في ها الدالَّة س يتم تفقُّد الجدول ل تحديد فيما إذا كانت نتيجة قيم المُعطيات متوفِّرةً ب الفعل أم لا . عند ها وببساطة سَتُعاد قيمة النتيجة المُخَزَّنة وَإن كان العكس فَ س يتم تثمين الدالَّة وَيُضاف مُدخَل جديد إلى جدول المُشاهدات لِيُعاد استخدام ه لاحقًا . قد يؤدِّي التثمين الكسول إلى نقص في الذكرة اللّازمة للبرامج ( المحجوزة ل ها ) ؛ لأنَّ القيم تُنسَئ عند الحاجة إلي ها . و من الصَّعب دمج التثمين الكسول مع المَزايا الأمريَّة مثل استيعاب الأخطاء وَالدخل / الخرج ، لأنّ ترتيب العمليّات يصبح غيرَ مُحدَّدٍ . وَقد يسبّب التثمين الكسول تسرب الذاكرة . عكس التثمين الكسول هو « التثمين اللَّهوف » ( eager evaluation ) ؛ وَأحيانًا يُعرَف ب اسم التثمين الصارم ( strict evaluation ) . و لقد وظِّف التثمين اللَّهوف كاستراتيجيّة تثمين في أغلب لُغات البرمجة . لمحة تاريخيّة قُدِّمَ التثمين الكسول من أجل حسابات اللامدا من قِبَل كريستوفر وادز - ورث وَباستقلالٍ من أجل لُغات البرمجة من قِبَل بيتر هيندرسن وَجيمس حيرم موريس وَدانيال بول فريدمان وَديفيد س . وايز . التطبيقات يُستخدم التثمين المؤجَّل ( Delayed evaluation ) تحديدًا في لُغات البرمجة الوظيفيَّة . ف عند استخدام التثمين المؤجَّل ، لا يتم تثمين التعبير عند إسناد ه إلى مُتَغَيِّر بل يُثَمَّن عند الحاجة ل إنتاج قيمة التعبير . هذه إفادة كمثال ، x : = expression ; ( إسناد نتيجة التعبير إلى مُتَغَيِّر ) . بوضوحٍ ، تَمَّ استدعاء التعبير بُغية تثمين ه وَوُضِعَت النتيجة في x ، لكن يتم تعليق ما بداخل x لِحين احتياج قيمة ه و ذٰلك ب استخدام فهرس يقود إلى x في تعبيرٍ ما لاحِقٍ و قد يكون هذا التعبير أيضًا مؤجّلًا ، وأخيرًا تُشَذَّب شجرة الاعتماديَّات النامية هذه ل إنتاج بعض الرموز الّتي يُفَضَّل رؤية ها . من فوائد التثمين المؤجَّل قدرة ه على إنشاء قوائم لانهائيَّة قابلة للحِساب ب دون تداخل الحلقات اللَّانهائيَّة أو الحجم في الحِساب . كمثال ، يُمكن إنشاء دالَّة تُنشِئ قائمة لانهائيَّة ( تُدعى غالبًا « جريان » ) من أعداد فيبوناتشي . إنَّ حِساب عدد فيبوناتشي ي ما - وليكن « ن » - س يكون بكلّ بساطة استخلاصًا ل هٰذا العنصر - الّذي هو العدد « ن » - من القائمة اللَّانهائيَّة ، مُجبرًا ب ذٰلك على تثمين أوَّل ن عنصر من القائمة . كمثال ، يُمكن في لغة البرمجة هاسكل كتابة قائمة بكلّ أعداد فيبوناتشي ك التالي : fibs = : : zipWith ( + ) fibs ( tail fibs ) في نحويَّة هاسكل ، « : » تُضيف عنصرًا إلى بداية القائمة وَ « tail » تعود بالقائمة ب دون عنصر ها الأوَّل وَ « zipWith » تَستَخدِم دالَّة مُعَيَّنة ( في حالة نا هذه هي الجمع « + » ) ل جمع العناصر المُتوافقة لِكلا القائمتين ب هدف إنتاج قائمة ثالثة . يجب أن يكون المبرمج حذرًا وَدقيقًا ؛ لأنّه يتم فقط تثمين القيم اللّازمة ل إنتاج نتيجة معيّنة . و مع ذلك ، قد تؤدّي بعض الحسابات إلى محاولة البرنامج لتثمين عدد لا حصر ل ه من العناصر ؛ على سبيل المثال ، طلب طول القائمة أو محاولة جمع عناصر القائمة ب عملية الطي ي يؤدي ب البرنامج إمَّا إلى فشل ال إنهاء أو نفاد الذاكرة . بُنى التحكّم في كلّ اللّغات « اللّهوفة » تقريبًا ، يتمّ تثمين الإفادة « if » ب أسلوب كسولٍ . if a then b else c سيتمّ تثمين ( a ) ، وَ إذا وَفقط إذا ثُمِّنَت ( a ) ل تكون صح « true » سيتمّ تثمين ( b ) وَإلّا سيتمّ تثمين ( c ) . و ب ذٰلك لن يتمّ تثمين واحد من ( b ) وَ ( c ) . بالمُقابِل ، س يكون السلوك المُتَوَقَّع هو هذا : define f ( x , y ) = * x set k = f ( d , e ) سيتمّ تثمين ( e ) عند حِساب قيمة f ( d , e ) و على الرُّغم من ذلك فقيمة ( e ) غير مُستخدمة في الدالَّة f . و ب التالي تعتمد بُنى التحكّم المُعرَّفة من قِبَل المُستَخدِم على النحويَّة المضبوطة ، كمثال : define g ( a , b , c ) = if a then b else c l = g ( h , i , j ) سيتمّ تثمين كُلٍّ من ( i ) وَ ( j ) في اللُّغة اللَّهوفة . بينما في اللُّغة الكسولة ، l ' = if h then i else j سيتمّ تثمين إمَّا ( i ) أو ( j ) ، و لن يتمّ تثمين كلي هما معًا أبدًا . يسمَح التثمين الكسول ب تعريف بُنى التحكّم طبيعيًّا ، وَ لٰكن لا يسمح ل ها أن تكون مُدمَجة أو كتقنيّات وقت - ال تجميع . ف إذا كان لِـ ( i ) أو ( j ) آثارًا جانبيّةً أو أثارت أخطاءً في وقت التشغيل ، عن ها س تكون الاختلافات غير الملحوظة بين ( l ) وَ ( l ' ) مُعَقَّدَةً . وَمن المُمكن عادةً إنشاء بُنى تحكّمٍ كسولة يُعرّف ها المُستخدِم كَدوالٍّ في اللُّغات اللَّهوفة ، ل ذٰلك قد تُزاح تلك الدَّوال من نحويَّة اللُّغة عند التثمين اللَّهوف : غالبًا ما يُحتَاج ادّثار جسد الشِفرة ( مثل : ( i ) وَ ( j ) ) ليصبح قيمة الدالَّة ، و لذٰلك يتمّ فقط تنفيذ ها عند ال استدعاء . يُدعى التثمين قصير ال دوران ( وَيُسمّى أيضًا : تثمين دُوني ي أو تثمين مَكارثي ) لِبُنى التحكّم البوليانيّة ( المنطقيّة ) تثمينًا « كسولًا » . العمل مع بُنى بيانات أزليّة توفّر العديد من اللُّغات مفهوم « بُنى - البيانات الأزليّة ( لا محدودة ) » \ . و يسمح ذلك ب تعريف البيانات كمجالات أزليّة أو كتعاوديّة غير منتهية ( unending recursion ) ، لكن يتمّ حساب القيم الفعليّة عندما نحتاج ها ف حسب . تفقّد هذا المِثال المتواضع ؛ و هو برنامج في لغة هاسكل : number FromInfiniteL ist\ : : Int - > Int number FromInfinite L ist n = infinity ! ! n - 1 where infinity = [ 1 . . ] main = print $ number FromInfinite L ist 4 في الدالَّة number FromInfinite L ist ، إنّ قيمة infinity هي مجال لا محدود ، ولحين احتياجه يتمّ تثمين المجال وصولًا إلى المؤشِّر ( index ) المطلوب . قائمة الأنماط الناجحة المراجع مصادر قراءة موسَّعة PhD th esis , Oxford University أنماط التصميم John Hugh es . " Why functio nal programming matters " . مجلة الحاسوب - Special issue on lazy functio nal programming . VolumeIssue A pril Philip Wadler . " How to replace failure by a list of successes a method for exception handling , backtracking , and pattern matching in lazy functional languages " . Functional Programming Languages and Computer A rchitecture . Lecture Notes in Computer Science , Volum e 1985 , الكسل في اللُّغات الصَّارمة Philip Wadler , Walid Taha , and David MacQueen . " How to add laziness to a strict language , without even being odd " . Workshop on Standard ML , Baltimore , September تدوينات ل علماء الحاسوب \ . " The Point of Laziness " Lennart A ugustsson . " More points for lazy evaluation " روابط خارجيّة Lazy Evaluation at the Portland Pattern Repository Lazy evaluation at Haskell Wiki The Incomplete Guide to Lazy Evaluation ( in Haskell ) – A series of tutorials on lazy evaluation in Haskell : How it works , how it h elps making code more modular , and other things . Functio nal programming in Python becomes lazy Lazy function argument evaluation in the D language Lazy evaluation macros in Nemerle Lambda calculus in Boost Libraries in C + + language Lazy Evaluation in Perl تحقيق أمثلية المجمع إستراتيجية تثمين تنفيذ للغات البرمجة الوظيفية