استراتيجية التقييم

في لغة البرمجة ، استراتيجية التقييم هي مجموعة من القواعد لتقييم التعبيرات. [1] غالبًا ما يستخدم المصطلح للإشارة إلى المفهوم الأكثر تحديدًا لاستراتيجية تمرير المعلمات [2] التي تحدد نوع القيمة التي يتم تمريرها إلى الوظيفة لكل معلمة ( استراتيجية الربط ) [3] وما إذا كان سيتم تقييم معلمات استدعاء الوظيفة، وإذا كان الأمر كذلك، فبأي ترتيب ( ترتيب التقييم ). [4] مفهوم استراتيجية الاختزال مميز، [5] على الرغم من أن بعض المؤلفين يخلطون بين المصطلحين ولا يتم الاتفاق على تعريف كل مصطلح على نطاق واسع. [6]

للتوضيح، f(a,b)قد يؤدي تنفيذ استدعاء دالة إلى تقييم الحجج أولاً aوتخزين bالنتائج في مراجع أو مواقع ذاكرة ref_aثم ref_bتقييم نص الدالة باستخدام تلك المراجع التي تم تمريرها. يمنح هذا الدالة القدرة على البحث عن قيم الحجج الأصلية التي تم تمريرها من خلال إلغاء الرجوع إلى المعلمات (تستخدم بعض اللغات مشغلات محددة لأداء هذا)، وتعديلها عبر التعيين كما لو كانت متغيرات محلية، وإرجاع القيم عبر المراجع. هذه هي استراتيجية تقييم الاستدعاء حسب المرجع. [7]

استراتيجية التقييم هي جزء من دلالات تعريف لغة البرمجة. بعض اللغات، مثل PureScript ، لها متغيرات مع استراتيجيات تقييم مختلفة. بعض اللغات الإعلانية ، مثل Datalog ، تدعم استراتيجيات تقييم متعددة. بعض اللغات تحدد اتفاقية استدعاء . [ يحتاج إلى توضيح ]

طاولة

هذا جدول لاستراتيجيات التقييم واللغات التمثيلية حسب السنة التي تم تقديمها فيها. يتم سرد اللغات التمثيلية بالترتيب الزمني، بدءًا من اللغة (اللغات) التي قدمت الاستراتيجية، متبوعة باللغات البارزة التي تستخدم الاستراتيجية. [8] : 434 

استراتيجية التقييم اللغات التمثيلية سنة التقديم لأول مرة
الاتصال عن طريق المرجع فورتران II، PL/I 1958
الاتصال حسب القيمة ALGOL ، C ، مخطط ، MATLAB [9] 1960
اتصل بالاسم ALGOL 60 ، محاكاة 1960
الاتصال عن طريق النسخ والاستعادة فورتران الرابع ، آدا [10] 1962
نداء التوحيد برولوج 1965 [11] [12]
اتصل حسب الحاجة SASL ، [13] هاسكل ، R [14] 1971 [15]
الاتصال عن طريق المشاركة كلو ، جافا ، بايثون ، روبي ، جوليا 1974 [16]
معلمات الاتصال حسب المرجع C++ ، PHP ، [17] C# ، [18] Visual Basic .NET [19] 1985 [20]
الاتصال بالإشارة إلى الثابت سي++ ، سي 1985 [20]

أوامر التقييم

في حين أن ترتيب العمليات يحدد شجرة بناء الجملة المجردة للتعبير، فإن ترتيب التقييم يحدد الترتيب الذي يتم به تقييم التعبيرات. على سبيل المثال، برنامج Python

def  f ( x ): 
    print ( x ,  end = '' ) 
    return  x

طباعة ( f ( 1 )  +  f ( 2 النهاية = '' )

المخرجات 123بسبب ترتيب التقييم من اليسار إلى اليمين في Python، ولكن برنامجًا مشابهًا في OCaml :

دع  f  x  =  print_int  x ;  x  ;; 
print_int  ( f  1  +  f  2 )

المخرجات 213بسبب ترتيب التقييم من اليمين إلى اليسار في OCaml.

ترتيب التقييم مرئي بشكل أساسي في الكود مع الآثار الجانبية ، ولكنه يؤثر أيضًا على أداء الكود لأن الترتيب الصارم يمنع جدولة التعليمات . لهذا السبب، تركت معايير اللغة مثل C++ الترتيب غير محدد تقليديًا، على الرغم من أن لغات مثل Java وC# تحدد ترتيب التقييم من اليسار إلى اليمين [8] : 240–241  ومعيار C++17 أضاف قيودًا على ترتيب التقييم. [21]

تقييم صارم

الترتيب التطبيقي هو مجموعة من أوامر التقييم حيث يتم تقييم وسيطات الدالة بالكامل قبل تطبيق الدالة. [22] وهذا له تأثير جعل الدالة صارمة ، أي أن نتيجة الدالة غير محددة إذا كانت أي من الوسيطات غير محددة، لذلك يُطلق على تقييم الترتيب التطبيقي عادةً اسم التقييم الصارم . علاوة على ذلك، يتم إجراء استدعاء الدالة بمجرد مواجهتها في إجراء، لذلك يُطلق عليه أيضًا التقييم الحريص أو التقييم الجشع . [23] [24] يشير بعض المؤلفين إلى التقييم الصارم باسم "الاستدعاء بالقيمة" نظرًا لأن استراتيجية ربط الاستدعاء بالقيمة تتطلب تقييمًا صارمًا. [4]

تقوم لغة Common Lisp و Eiffel وJava بتقييم وسيطات الوظيفة من اليسار إلى اليمين. تترك لغة C الترتيب غير محدد. [25] يتطلب Scheme أن يكون ترتيب التنفيذ هو التنفيذ المتسلسل لتبديل غير محدد للوسيطات. [26] وبالمثل، تترك لغة OCaml الترتيب غير محدد، ولكنها في الممارسة العملية تقيم الوسيطات من اليمين إلى اليسار بسبب تصميم آلتها المجردة . [27] كل هذه التقييمات صارمة.

تقييم غير صارم

ترتيب التقييم غير الصارم هو ترتيب تقييم غير صارم، أي أن الدالة قد تعيد نتيجة قبل تقييم جميع وسيطاتها بالكامل. [28] : 46–47  المثال النموذجي هو تقييم الترتيب الطبيعي ، والذي لا يقيم أيًا من الوسيطات حتى تكون هناك حاجة إليها في جسم الدالة. [29] يتمتع تقييم الترتيب الطبيعي بخاصية أنه ينتهي بدون خطأ كلما انتهى أي ترتيب تقييم آخر بدون خطأ. [30] يأتي اسم "الترتيب الطبيعي" من حساب لامدا، حيث سيجد الاختزال بالترتيب الطبيعي شكلًا طبيعيًا إذا كان هناك واحد (إنها استراتيجية اختزال "تطبيعية" ). [31] يتم تصنيف التقييم الكسول في هذه المقالة على أنه تقنية ملزمة وليس ترتيب تقييم. ولكن هذا التمييز لا يتم اتباعه دائمًا ويعرف بعض المؤلفين التقييم الكسول على أنه تقييم بالترتيب الطبيعي أو العكس، [22] [32] أو يخلطون بين عدم الصرامة والتقييم الكسول. [28] : 43–44 

تستخدم التعبيرات المنطقية في العديد من اللغات شكلاً من أشكال التقييم غير الصارم يسمى تقييم الدائرة القصيرة ، حيث يقيم التقييم التعبير الأيسر ولكن قد يتخطى التعبير الأيمن إذا كان من الممكن تحديد النتيجة - على سبيل المثال، في تعبير منفصل (OR) حيث trueيتم مواجهته، أو في تعبير عطف (AND) حيث falseيتم مواجهته، وما إلى ذلك. [32] وبالمثل تستخدم التعبيرات الشرطية التقييم غير الصارم - يتم تقييم أحد الفروع فقط. [28]

مقارنة بين التقييم حسب الترتيب التطبيقي والتقييم حسب الترتيب الطبيعي

مع تقييم الترتيب العادي، سيتم تجاهل التعبيرات التي تحتوي على حساب مكلف أو خطأ أو حلقة لا نهائية إذا لم تكن هناك حاجة إليها، [4] مما يسمح بتحديد بنيات تدفق التحكم المحددة من قبل المستخدم، وهي ميزة غير متوفرة مع تقييم الترتيب التطبيقي. يستخدم تقييم الترتيب العادي هياكل معقدة مثل thunks للتعبيرات غير المقيمة، مقارنة بمكدس النداء المستخدم في تقييم الترتيب التطبيقي. [33] كان تقييم الترتيب العادي يفتقر تاريخيًا إلى أدوات تصحيح الأخطاء القابلة للاستخدام بسبب تعقيده. [34]

استراتيجيات الربط الصارمة

الاتصال حسب القيمة

في الاستدعاء بالقيمة (أو التمرير بالقيمة)، يتم ربط القيمة المقيمة لتعبير الوسيطة بالمتغير المقابل في الدالة (غالبًا عن طريق نسخ القيمة إلى منطقة ذاكرة جديدة). إذا كانت الدالة أو الإجراء قادرًا على تعيين قيم لمعلماتها، فسيتم تعيين متغيرها المحلي فقط - أي أن أي شيء يتم تمريره إلى استدعاء الدالة لا يتغير في نطاق المتصل عندما تعود الدالة. على سبيل المثال، في باسكال ، سيؤدي تمرير مصفوفة بالقيمة إلى نسخ المصفوفة بأكملها، وستكون أي طفرات في هذه المصفوفة غير مرئية للمتصل: [35]

البرنامج الرئيسي ؛ يستخدم crt ؛ 
 

الإجراء PrintArray ( a : مجموعة من الأعداد الصحيحة ) ؛ var i : عدد صحيح ؛ تبدأ من i := Low ( a ) إلى High ( a ) وتكتب ( a [ i ]) ؛ وتكتب WriteLn () ؛ وتنتهي ؛    

   

        
    
  


الإجراء تعديل ( الصف : مجموعة من الأعداد الصحيحة ) ؛ البدء بطباعة المصفوفة ( الصف ) ؛ // 123 الصف [ 1 ] := 4 ؛ طباعة المصفوفة ( الصف ) ؛ // 143 النهاية ؛       
  
   
    
   


Var 
A : مجموعة من الأعداد الصحيحة ؛ تبدأ A := [ 1 ، 2 ، 3 ] ؛ PrintArray ( A ) ؛ // 123 تعديل ( A ) ؛ PrintArray ( A ) ؛ // 123 نهاية .       

    
   
  
   

الانحراف الدلالي

بالمعنى الدقيق للكلمة، في ظل استدعاء القيمة، لا يمكن للمتصل رؤية أي عمليات يتم إجراؤها بواسطة الروتين المستدعى، بخلاف كونها جزءًا من قيمة الإرجاع. [16] وهذا يعني شكلًا من أشكال البرمجة الوظيفية البحتة في دلالات التنفيذ. ومع ذلك، أصبح التعبير "استدعاء القيمة حيث تكون القيمة مرجعًا" شائعًا في بعض اللغات، على سبيل المثال، مجتمع Java. [36] بالمقارنة مع التمرير التقليدي بالقيمة، فإن القيمة التي يتم تمريرها ليست قيمة كما يفهمها المعنى العادي للقيمة، مثل عدد صحيح يمكن كتابته كحرفي، ولكنها مقبض مرجعي داخلي للتطبيق . الطفرات في مقبض المرجع هذا مرئية في المتصل. وبسبب الطفرة المرئية، يُشار إلى هذا الشكل من "الاتصال بالقيمة" بشكل أكثر ملاءمة باسم الاتصال بالمشاركة. [16]

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

الاتصال عن طريق المرجع

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

بسبب الاختلاف في بناء الجملة، فإن الفرق بين الاستدعاء بالإشارة (حيث يكون نوع المرجع ضمنيًا) والاستدعاء بالمشاركة (حيث يكون نوع المرجع صريحًا) غالبًا ما يكون غير واضح للوهلة الأولى. اختبار بسيط هو ما إذا كان من الممكن كتابة دالة تقليدية في swap(a, b)اللغة. [36] على سبيل المثال في فورتران:

برنامج رئيسي 
ضمني لا يوجد عدد صحيح :: أ = 1 عدد صحيح :: ب = 2 استدعاء مبادلة ( أ ، ب ) طباعة * ، أ ، ب ! 2 1 يحتوي على برنامج     فرعي مبادلة ( أ ، ب ) عدد صحيح ، نية ( إدخال وإخراج ) :: أ ، ب عدد صحيح :: درجة الحرارة درجة الحرارة = أ أ = ب ب = درجة الحرارة نهاية البرنامج الفرعي مبادلة نهاية البرنامج الرئيسي    
        
        
     
        

 
            
          
          
          
          
    

لذلك، فإن نية Fortran inoutتنفذ استدعاءً بالمرجع؛ يمكن تحويل أي متغير ضمناً إلى مقبض مرجعي. وعلى النقيض من ذلك، فإن أقرب ما يمكن الحصول عليه في Java هو:

class  Main { static class Box { int value ; public Box ( int value ) { this.value = value ; } } static void swap ( Box a , Box b ) { int temp = a.value ; a.value = b.value ; b.value = temp ; } public static void main ( String [ ] args ) { Box a = new Box ( 1 ) ; Box b = new Box ( 2 ) ; swap ( a , b ) ; System.out.println ( String.format ( " % d % d " , a.value , b.value ) ) ; } } // output : 2 1 
       
         
           
              
        
    
          
           
          
          
    
         
            
            
         
          
    


حيث يجب استخدام نوع صريح Boxلتقديم مقبض. Java تعتمد على الاستدعاء عن طريق المشاركة ولكنها لا تعتمد على الاستدعاء عن طريق المرجع. [36]

الاتصال عن طريق النسخ والاستعادة

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

إن دلالات استدعاء النسخ والاستعادة تشبه في كثير من الحالات استدعاء المرجع، ولكنها تختلف عندما يكون هناك اسم مستعار لحجتين أو أكثر للوظيفة ( أي الإشارة إلى نفس المتغير في بيئة المتصل). في استدعاء المرجع، فإن الكتابة إلى حجة واحدة ستؤثر على الحجة الأخرى أثناء تنفيذ الوظيفة. في استدعاء النسخ والاستعادة، فإن الكتابة إلى حجة واحدة لن تؤثر على الحجة الأخرى أثناء تنفيذ الوظيفة، ولكن في نهاية الاستدعاء، قد تختلف قيم الحجتين، ومن غير الواضح أي الحجة يتم نسخها أولاً وبالتالي ما هي القيمة التي يتلقاها متغير المتصل. [38] على سبيل المثال، تحدد Ada أن تعيين النسخ لكل معلمة in outأو outيحدث بترتيب عشوائي. [39] من البرنامج التالي (غير قانوني في Ada 2012) [40] يمكن ملاحظة أن سلوك GNAT هو النسخ بترتيب من اليسار إلى اليمين عند العودة:

مع  Ada.Text_IO ؛  استخدم  Ada.Text_IO ؛

إجراء  Test_Copy_Restore  هو 
  إجراء  Modify  ( A ,  B  : in  out  Integer )  يبدأ 
  بـ 
      A  :=  A  +  1 ؛ 
      B  :=  B  +  2 ؛ 
  نهاية  Modify ؛ 
  X  :  Integer  :=  0 ؛ 
بداية 
  Modify ( X ,  X 
  Put_Line ( "X = "  &  Integer ' Image ( X )); 
نهاية  Test_Copy_Restore ؛ 
-- $ gnatmake -gnatd.E test_copy_restore.adb؛ ./test_copy_restore 
-- test_copy_restore.adb:12:10: تحذير: يتداخل الفعلي القابل للكتابة لـ "A" مع الفعلي لـ "B" [-gnatw.i] 
-- X = 2

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

عندما يتم تمرير المرجع إلى المتصل غير مهيأ (على سبيل المثال، outمعلمة في Ada بدلاً من in outمعلمة)، يمكن تسمية استراتيجية التقييم هذه بـ "المكالمة حسب النتيجة".

لقد اكتسبت هذه الاستراتيجية اهتمامًا في عمليات المعالجة المتعددة واستدعاءات الإجراءات عن بعد ، [41] على عكس الاستدعاء عن طريق المرجع، فهي لا تتطلب اتصالاً متكررًا بين خيوط التنفيذ للوصول إلى المتغيرات.

الاتصال عن طريق المشاركة

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

تم ملاحظة هذه التقنية لأول مرة بواسطة باربرا ليسكوف في عام 1974 للغة CLU . [16] يتم استخدامها بواسطة العديد من اللغات الحديثة مثل بايثون (القيم المشتركة تسمى "كائنات")، [42] جافا (كائنات)، روبي (كائنات)، جافا سكريبت (كائنات)، سكيم (هياكل البيانات مثل المتجهات)، [43] أبل سكريبت (قوائم وسجلات وتواريخ وكائنات نصية)، أو كامال و إم إل (مراجع وسجلات ومصفوفات وكائنات وأنواع بيانات مركبة أخرى)، مابل (جداول وجداول rtables)، وتي سي إل (كائنات). [44] مصطلح "الاستدعاء عن طريق المشاركة" كما هو مستخدم في هذه المقالة ليس شائع الاستخدام؛ المصطلحات غير متسقة عبر مصادر مختلفة. على سبيل المثال، في مجتمع جافا، يقولون أن جافا هي استدعاء بالقيمة. [36]

بالنسبة للكائنات غير القابلة للتغيير ، لا يوجد فرق حقيقي بين الاستدعاء بالمشاركة والاستدعاء بالقيمة، إلا إذا كانت هوية الكائن مرئية في اللغة. يعد استخدام الاستدعاء بالمشاركة مع الكائنات القابلة للتغيير بديلاً لمعلمات الإدخال/الإخراج : لا يتم تعيين المعلمة (لا يتم استبدال الوسيطة ولا يتم تغيير هوية الكائن)، ولكن يتم تحوير الكائن (الوسيطة). [45]

على سبيل المثال، في Python، تكون القوائم قابلة للتغيير ويتم تمريرها من خلال الاستدعاء عن طريق المشاركة، لذا:

def  f ( a_list ): 
    a_list . append ( 1 )

م  =  [] 
ف ( م ) 
طباعة ( م )

المخرجات [1]لأن appendالطريقة تعدل الكائن الذي تم استدعاؤها عليه.

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

def  f ( a_list ): 
    a_list  =  a_list  +  [ 1 ] 
    print ( a_list )  # [1]

م  =  [] 
ف ( م ) 
طباعة ( م )  # []

الاتصال حسب العنوان

الاستدعاء بالعنوان أو التمرير بالعنوان أو الاستدعاء/التمرير بالمؤشر هي طريقة تمرير معلمات حيث يتم تمرير عنوان الوسيطة كمعلمة رسمية. داخل الدالة، يمكن استخدام العنوان (المؤشر) للوصول إلى قيمة الوسيطة أو تعديلها. على سبيل المثال، يمكن تنفيذ عملية المبادلة على النحو التالي في C: [46]

#تضمين <stdio.h> 

مبادلة الفراغ ( int * a ، int * b ) { int temp = * a ؛ * a = * b ؛ * b = temp ؛ }     
       
      
      


int main () { int a = 1 ; int b = 2 ; swap ( &a a ، & b ); printf ( "%d %d" , a , b ); // 2 1 return 0 ; }  
       
       
     
       
     

يتعامل بعض المؤلفين &مع استدعاء . كجزء من بناء الجملة swap. وفقًا لهذا الرأي، تدعم لغة C استراتيجية تمرير المعلمات عن طريق الاستدعاء. [47] يتبنى مؤلفون آخرون وجهة نظر مختلفة مفادها أن التنفيذ المقدم لـ swapفي لغة C هو مجرد محاكاة للاستدعاء عن طريق المرجع باستخدام المؤشرات. [48] وفقًا لوجهة النظر "المحاكاة" هذه، فإن المتغيرات القابلة للتغيير في لغة C ليست من الدرجة الأولى (أي أن قيم l ليست تعبيرات)، بل أنواع المؤشرات هي من الدرجة الأولى. في هذا الرأي، يعد برنامج المبادلة المقدم سكرًا لغويًا لبرنامج يستخدم المؤشرات في جميع أنحاءه، [49] على سبيل المثال هذا البرنامج ( readوتمت assignإضافته لتسليط الضوء على أوجه التشابه مع Boxبرنامج المشاركة عن طريق الاستدعاء في Java أعلاه):

#تضمين <stdio.h> 

int read ( int * p ) { return * p ; }   
   


تعيين باطل ( int * p ، int v ) { * p = v ؛ }     
    


void swap ( int * a ، int * b ) { int temp_storage ؛ int * temp = & temp_storage ؛ تعيين ( temp ، قراءة ( a ))؛ تعيين ( a ، قراءة ( b ))؛ تعيين ( b ، قراءة ( temp ))؛ }     
         
     
     
     


int main () { int a_storage ; int * a = & a_storage ; int b_storage ; int * b = & b_storage ; assign ( a , 1 ); assign ( b , 2 ); swap ( a , b ); printf ( "%d %d" , read ( a ), read ( b )); // 2 1 return 0 ; }  
         
         
    
    
     
       
     

نظرًا لأن هذا البرنامج swapيعمل على المؤشرات ولا يمكنه تغيير المؤشرات نفسها، ولكن فقط القيم التي تشير إليها المؤشرات، فإن هذا الرأي يرى أن استراتيجية التقييم الرئيسية في لغة C تشبه إلى حد كبير استراتيجية الاستدعاء عن طريق المشاركة.

يزيد C++ من تعقيد المشكلة من خلال السماح swapبالإعلان عنها واستخدامها باستخدام صيغة "مرجعية" خفيفة الوزن للغاية: [50]

مبادلة فارغة ( int & a ، int & b ) { int temp = a ؛ a = b ؛ b = temp ؛ }     
       
      
      


int main () { int a = 1 ؛ int b = 2 ؛ swap ( a ، b std :: cout << a << b << std :: endl ؛ // 2 1 return 0 ؛ }  
       
       
     
           
     

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

نداء التوحيد

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

استراتيجيات غير ملزمة بشكل صارم

اتصل بالاسم

الاستدعاء بالاسم هو استراتيجية تقييم حيث لا يتم تقييم وسيطات الدالة قبل استدعاء الدالة - بل يتم استبدالها مباشرة في نص الدالة (باستخدام الاستبدال المتجنب للالتقاط ) ثم تُترك للتقييم كلما ظهرت في الدالة. إذا لم يتم استخدام وسيطة في نص الدالة، فلن يتم تقييم الوسيطة أبدًا؛ إذا تم استخدامها عدة مرات، فسيتم إعادة تقييمها في كل مرة تظهر فيها. (انظر جهاز جينسن لتقنية برمجة تستغل هذا.)

في بعض الأحيان، يكون تقييم الاستدعاء بالاسم أفضل من تقييم الاستدعاء بالقيمة. إذا لم يتم استخدام وسيطة الدالة في الدالة، فإن الاستدعاء بالاسم سيوفر الوقت من خلال عدم تقييم الوسيطة، في حين أن الاستدعاء بالقيمة سيقيمها بغض النظر عن ذلك. إذا كانت الوسيطة عبارة عن حساب غير منتهٍ، فإن الميزة هائلة. ومع ذلك، عند استخدام وسيطة الدالة، غالبًا ما يكون الاستدعاء بالاسم أبطأ، مما يتطلب آلية مثل thunk .

تستطيع لغات .NET محاكاة النداء بالاسم باستخدام المندوبين أو Expression<T>المعلمات. ويؤدي الأخير إلى إعطاء شجرة بناء جملة مجردة للوظيفة. توفر Eiffel وكلاء، يمثلون عملية يتم تقييمها عند الحاجة. توفر Seed7 النداء بالاسم مع معلمات الوظيفة. يمكن لبرامج Java إنجاز تقييم كسول مماثل باستخدام تعبيرات lambda والواجهة java.util.function.Supplier<T>.

اتصل حسب الحاجة

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

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

في تنفيذ R لـ call by need، يتم تمرير جميع الوسائط، مما يعني أن R يسمح بتأثيرات جانبية تعسفية.

التقييم الكسول هو التنفيذ الأكثر شيوعًا لدلالات الاستدعاء حسب الحاجة، ولكن توجد اختلافات مثل التقييم المتفائل. تنفذ لغات .NET الاستدعاء حسب الحاجة باستخدام النوع Lazy<T>.

يعد تقليل الرسم البياني تنفيذًا فعالًا للتقييم الكسول.

الدعوة عن طريق التوسع الكلي

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

الاتصال بالمستقبل

"الاستدعاء بالمستقبل"، والمعروف أيضًا باسم "الاستدعاء الموازي بالاسم" أو "التقييم المتساهل"، [51] عبارة عن استراتيجية تقييم متزامنة تجمع بين الدلالات غير الصارمة والتقييم الحريص. تتطلب الطريقة جدولة ديناميكية دقيقة ومزامنة ولكنها مناسبة للآلات المتوازية بشكل كبير.

تخلق الإستراتيجية مستقبلاً (وعدًا) لجسم الدالة وكل وسيطة من وسيطاتها. يتم حساب هذه المستقبلات بالتزامن مع تدفق بقية البرنامج. عندما يتطلب المستقبل A قيمة مستقبل آخر B لم يتم حسابه بعد، يتم حظر المستقبل A حتى ينتهي المستقبل B من الحساب ويكون له قيمة. إذا انتهى المستقبل B بالفعل من الحساب، يتم إرجاع القيمة على الفور. يتم حظر الشرطيات حتى يتم تقييم شرطها، ولا تنشئ لامدا مستقبلات حتى يتم تطبيقها بالكامل. [52]

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

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

f x = 1 / x g y = 1 main = print ( g ( f 0 ))   
   
     

قد يكون هناك إما gانتهاء قبل f، وإخراج 1، أو قد يؤدي إلى خطأ بسبب التقييم 1/0. [28]

إن عملية الاستدعاء بالمستقبل تشبه عملية الاستدعاء حسب الحاجة في أن القيم تُحسب مرة واحدة فقط. ومع التعامل الدقيق مع الأخطاء وعدم الإنهاء، وخاصة العقود الآجلة المنتهية في منتصف الطريق إذا تم تحديد أنها لن تكون هناك حاجة إليها، فإن عملية الاستدعاء بالمستقبل لها أيضًا نفس خصائص الإنهاء مثل تقييم الاستدعاء حسب الحاجة. [52] ومع ذلك، قد تؤدي عملية الاستدعاء بالمستقبل إلى عمل مضاربي غير ضروري مقارنة بعملية الاستدعاء حسب الحاجة، مثل التقييم العميق لبنية بيانات كسولة. [28] ويمكن تجنب ذلك باستخدام العقود الآجلة الكسولة التي لا تبدأ الحساب حتى يتم التأكد من الحاجة إلى القيمة.

تقييم متفائل

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

انظر أيضا

مراجع

  1. ^ أراكي، شوتا؛ نيشيزاكي، شين-يا (نوفمبر 2014). "تقييم النداء بالاسم لحسابات RPC وRMI". نظرية وممارسة الحوسبة. ص. 1. doi :10.1142/9789814612883_0001. ISBN 978-981-4612-87-6تم الاسترجاع بتاريخ 21 أغسطس 2021 .
  2. ^ تورباك، فرانكلين؛ جيفورد، ديفيد (18 يوليو 2008). مفاهيم التصميم في لغات البرمجة. مطبعة معهد ماساتشوستس للتكنولوجيا. ص 309. رقم ISBN 978-0-262-30315-6.
  3. ^ Crank, Erik; Felleisen, Matthias (1991). "Parameter-passing and the lambda calculus". Proceedings of the 18th ACM SIGPLAN-SIGACT symposium on Principles of programming language - POPL '91 . p. 2. CiteSeerX 10.1.1.23.4385 . doi :10.1145/99583.99616. ISBN  0897914198. S2CID  5782416.
  4. ^ اي بي سي فيلهلم ، راينهارد. سيدل ، هيلموت (10 نوفمبر 2010). تصميم المترجم: الأجهزة الافتراضية. سبرينغر العلوم والإعلام التجاري. ص. 61. ردمك 978-3-642-14909-2.
  5. ^ نيتا ، ستيفانيا لوريدانا ؛ ميهايليسكو، ماريوس (2017). "مقدمة". العملي المتزامن هاسكل . ص. 3. دوى :10.1007/978-1-4842-2781-7_1. رقم ISBN 978-1-4842-2780-0.
  6. ^ Pierce, Benjamin C. (2002). Types and Programming Languages. MIT Press . ص 56. ISBN 0-262-16209-1.
  7. ^ Daniel P. Friedman; Mitchell Wand (2008). Essentials of Programming Languages ​​(third ed.). Cambridge, MA: The MIT Press . ISBN 978-0262062794.
  8. ^ ab Scott, Michael Lee (2016). Programming language pragmatics (الطبعة الرابعة). Waltham, MA: Elsevier. ISBN 9780124104778.
  9. ^ "تجنب النسخ غير الضرورية للبيانات - MATLAB & Simulink". www.mathworks.com . تم الاسترجاع في 2023-01-28 .
  10. ^ Hasti, Rebecca. "Parameter Passing". CS 536: Introduction to Programming Languages ​​and Compilers . University of Wisconsin . تم الاسترجاع في 22 أغسطس 2021 .
  11. ^ JA Robinson (يناير 1965). "منطق موجه للآلة يعتمد على مبدأ الحل". مجلة ACM . 12 (1): 23–41. doi : 10.1145/321250.321253 . S2CID  14389185.؛ هنا: القسم 5.8، ص 32
  12. ^ JA Robinson (1971). "المنطق الحسابي: الحوسبة الموحدة". ذكاء الآلة . 6 : 63-72.
  13. ^ باندي، آلان؛ والين، لينكولن (1984). "SASL". كتالوج أدوات الذكاء الاصطناعي . ص. 117. doi :10.1007/978-3-642-96868-6_222. ISBN 978-3-540-13938-6. ربما كانت اللغة الأولى التي استغلت قوة التقييم الكسول بشكل منهجي.
  14. ^ فاي، كولين (30 يوليو 2018). "حول التقييم الكسول". R-bloggers . تم الاسترجاع في 21 أغسطس 2021 .
  15. ^ وادزورث، كريستوفر ب. (1971). الدلالات والبراغماتيات في حساب لامدا (دكتوراه). جامعة أكسفورد.
  16. ^ abcde Liskov, Barbara; Atkinson, Russ; Bloom, Toby; Moss, Eliot; Schaffert, Craig; Scheifler, Craig; Snyder, Alan (October 1979). "CLU Reference Manual" (PDF) . مختبر علوم الكمبيوتر . معهد ماساتشوستس للتكنولوجيا. ص. 14-15. مؤرشف من الأصل (PDF) في 22 سبتمبر 2006. تم استرجاعه في 19 مايو 2011 .
  17. ^ "PHP: Passing by Reference - Manual". www.php.net . تم الاسترجاع في 2021-07-04 .
  18. ^ Wagner, Bill (12 أبريل 2023). "Passing Parameters - C# Programming Guide". Microsoft Docs . تم الاسترجاع في 2023-09-10 .
  19. ^ دولارد، كاثلين (15 سبتمبر 2021). "تمرير الوسائط حسب القيمة والمرجع - فيجوال بيسك". مستندات مايكروسوفت . تم الاسترجاع في 2023-09-10 .
  20. ^ ab "تاريخ C++". en.cppreference.com . تم الاسترجاع في 11 يونيو 2022 .
  21. ^ Filipek, Bartlomiej (16 أغسطس 2021). "ترتيب تقييم تعبيرات أكثر صرامة في C++17". C++ Stories . تم الاسترجاع في 24 أغسطس 2021 .
  22. ^ أبيلسون، هارولد ؛ سوسمان، جيرالد جاي (1996). "الترتيب الطبيعي والترتيب التطبيقي". بنية وتفسير برامج الكمبيوتر (الطبعة الثانية). كامبريدج، ماساتشوستس: مطبعة معهد ماساتشوستس للتكنولوجيا . رقم ISBN 0-262-01153-0. تم أرشفة النسخة الأصلية في 2005-03-02 . تم استرجاعها في 2006-03-06 .انظر أيضًا الحاشية رقم 576.
  23. ^ Reese, Richard M. (14 October 2015). تعلم البرمجة الوظيفية بلغة Java. Packt Publishing Ltd. ص. 106. ISBN 978-1-78528-935-4.
  24. ^ Antani, Ved; Timms, Simon; Mantyla, Dan (31 أغسطس 2016). JavaScript: Functional Programming for JavaScript Developers. Packt Publishing Ltd. ص. 614. ISBN 978-1-78712-557-5.
  25. ^ Seacord, Robert C. "EXP30-C. Do not depend on the order of evaluation for side effects". SEI CERT C Coding Standard . جامعة كارنيجي ميلون . تم الاسترجاع في 23 أغسطس 2021 .
  26. ^ Anglade, S.; Lacrampe, JJ; Queinnec, C. (أكتوبر 1994). "دلالات التوليفات في المخطط" (PDF) . مؤشرات ACM SIGPLAN Lisp . VII (4): 15–20. doi :10.1145/382109.382669. S2CID  2987427.
  27. ^ "لماذا يتم تقييم وسيطات دالة OCaml من اليمين إلى اليسار؟". OCaml . 30 نوفمبر 2017.
  28. ^ abcde Tremblay, G. (أبريل 2000). "التقييم المتساهل ليس صارمًا ولا كسولًا". لغات الكمبيوتر . 26 (1): 43–66. CiteSeerX 10.1.1.137.9885 . doi :10.1016/S0096-0551(01)00006-6. 
  29. ^ جورج، لاي (مارس 1987). التقييم الفعال للنظام الطبيعي من خلال معلومات الصرامة (ماجستير). جامعة يوتا. ص 10.
  30. ^ Borning, Alan (Autumn 1999). "Applicative vs Normal Order Evaluation in Functional Languages" (PDF) . CSE 505: Concepts of Programming Languages . University of Washington . تم الاسترجاع في 23 أغسطس 2021 .
  31. ^ مازولا، جيرينو؛ ميلميستر، جيرارد؛ وايسمان، جودي (21 أكتوبر 2004). الرياضيات الشاملة لعلماء الكمبيوتر 2. سبرينغر ساينس آند بيزنس ميديا. ص. 323. رقم ISBN 978-3-540-20861-7.
  32. ^ ab Sturm, Oliver (11 أبريل 2011). البرمجة الوظيفية بلغة سي شارب: تقنيات البرمجة الكلاسيكية للمشاريع الحديثة. جون وايلي وأولاده. ص 91. ISBN 978-0-470-74458-1.
  33. ^ مارلو، سيمون. "لماذا لا يمكنني الحصول على تتبع المكدس؟". ورشة عمل منفذي هاسكل 2012. تم الاسترجاع في 25 أغسطس 2021 .
  34. ^ نيلسون، هنريك (1999). "تتبع قطعة قطعة: تصحيح أخطاء بأسعار معقولة للغات الوظيفية الكسولة". وقائع المؤتمر الدولي الرابع لـ ACM SIGPLAN حول البرمجة الوظيفية . ص 36-47. CiteSeerX 10.1.1.451.6513 . doi :10.1145/317636.317782. ISBN  1581131119. S2CID  13954359.
  35. ^ "معلمات المصفوفة المفتوحة". www.freepascal.org . تم الاسترجاع في 20 يناير 2024 .
  36. ^ abcd "Java is Pass-by-Value, Dammit!". 16 مايو 2001. تم الاسترجاع في 2016-12-24 .
  37. ^ كوينين ، فرانس. "تمرير المعلمة". cgi.csc.liv.ac.uk . تم الاسترجاع 22 يناير 2024 .
  38. ^ "الدعوة عن طريق الإشارة، قضايا الأسماء المستعارة" (ملف PDF) . دورة MPRI 2-36-1: إثبات البرنامج (ملاحظات المحاضرة) . ص. 53.
  39. ^ دليل مرجعي للغة Ada 2022 (PDF) . 13 أكتوبر 2023. ص 215.
  40. ^ بارنز، جون (2013). Ada 2012 reasone: the language, the standard libraries (PDF) . هايدلبرغ: سبرينغر. ص. 15-16، 87-88. ISBN 978-3-642-45210-9.
  41. ^ Thurlow, Robert (مايو 2009). "RPC: مواصفات بروتوكول استدعاء الإجراء عن بعد الإصدار 2". tools.ietf.org . IETF . تم الاسترجاع في 7 أبريل 2018 .
  42. ^ لوند، فريدريك. "Call by Object". Effbot.org . مؤرشف من الأصل في 2011-05-19 . تم الاسترجاع في 2011-05-19 .
  43. ^ جونز، رايس برايس (2010). "هل يتم استدعاء المخطط حسب القيمة؟". مختبر لغات البرمجة CS 145 9: تمرير المعلمات . جامعة جورج واشنطن. مؤرشف من الأصل في 16 أكتوبر 2014. تم الاسترجاع في 20 يناير 2024 .
  44. ^ "إجراءات مكتبة Tcl - صفحة دليل Tcl_Obj". www.tcl.tk .
  45. ^ "CA1021: تجنب معلمات الخروج". مايكروسوفت. 15 نوفمبر 2016.
  46. ^ Leo, Ray (نوفمبر 1996). Little C++ (Made Easy). LeoSudo Inc. ص 79-80. ISBN 978-0-9654634-1-6.
  47. ^ داندامودي، سيفاراما ب. (15 يوليو 2005). دليل برمجة لغة التجميع في لينكس. سبرينغر ساينس آند بيزنس ميديا. ص 232. رقم ISBN 978-0-387-25897-3.
  48. ^ Srivastava, SK; Srivastava, Deepali (6 June 2018). C in Depth. BPB Publications. ص. 206. ISBN 978-93-87284-94-4.
  49. ^ "المتغيرات القابلة للتغيير وأنواع المرجع". okmij.org . تم الاسترجاع في 20 يناير 2024 .
  50. ^ فيرمير، ديرك (28 يونيو 2011). البرمجة متعددة النماذج باستخدام لغة سي++. سبرينغر ساينس آند بيزنس ميديا. ص 10-11. رقم ISBN 978-1-4471-0311-0.
  51. ^ McCollin, Thomas Gwynfryn; Morell, Tobias. "A Game of Paradigms: A Usability Study of Functional Idioms in Gameplay Programming" (PDF) . جامعة آلبورج. ص. 6. تم الاسترجاع في 11 يناير 2022 .
  52. ^ ab Schauser, Klaus E.; Goldstein, Seth C. (1995). "ما مقدار عدم الصرامة التي تتطلبها البرامج المتساهلة؟" (PDF) . وقائع المؤتمر الدولي السابع للغات البرمجة الوظيفية وهندسة الكمبيوتر - FPCA '95 . ص 216-225. doi :10.1145/224164.224208. ISBN 0897917197. S2CID  2045943 . تم الاسترجاع في 7 يناير 2022 .
  53. ^ إينالز، روبرت؛ جونز، سيمون بيتون (أغسطس 2003). "التقييم المتفائل: استراتيجية تقييم سريعة للبرامج غير الصارمة".

قراءة إضافية

  • بيكر فينش، كليم؛ كينج، ديفيد؛ هول، جون؛ تريندر، فيل (10 مارس 1999). "دلالات تشغيلية للمكالمات المتوازية حسب الحاجة" (ps) . تقرير بحثي . 99 (1). كلية الرياضيات والحوسبة، الجامعة المفتوحة.
  • إينالز، روبرت؛ بيتون جونز، سيمون (2003). التقييم المتفائل: استراتيجية تقييم سريعة للبرامج غير الصارمة (PDF) . المؤتمر الدولي حول البرمجة الوظيفية. مطبعة ACM.
  • لوداشر، بيرترام (2001-01-24). "ملاحظات محاضرات CSE 130". CSE 130: لغات البرمجة: المبادئ والنماذج .
  • بيرس، بنيامين سي. (2002). الأنواع ولغات البرمجة . مطبعة معهد ماساتشوستس للتكنولوجيا . رقم ISBN 0-262-16209-1.
  • سيستوفت، بيتر (2002). موغنسن، ت؛ شميدت، د؛ سودبورو، آي إتش (المحررون). إظهار اختزال حساب لامدا (ملف PDF) . مذكرات محاضرات في علوم الكمبيوتر. المجلد 2566. دار نشر سبرينغر. ص 420-435. رقم ISBN 3-540-00326-6. {{cite book}}: |work=تم تجاهله ( مساعدة )
  • "الاستدعاء بالقيمة والاستدعاء بالمرجع في برمجة C". شرح الاستدعاء بالقيمة والاستدعاء بالمرجع في برمجة C. مؤرشف من الأصل في 2013-01-21.
  • أداة عرض هندسة التفاعل التفاعلية عبر الإنترنت ، والتي تنفذ آلة تعتمد على الرسم البياني لعدة استراتيجيات تقييم شائعة.
Retrieved from "https://en.wikipedia.org/w/index.php?title=Evaluation_strategy&oldid=1247275836"
Original text
Rate this translation
Your feedback will be used to help improve Google Translate