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

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

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

استراتيجية التقييم هي جزء من دلالات تعريف لغة البرمجة. بعض اللغات، مثل (PureScript)، لديها متغيرات مع استراتيجيات تقييم مختلفة. تدعم بعض اللغات التصريحية ، مثل سجل البيانات (Datalog)، استراتيجيات تقييم متعددة. تحدد بعض اللغات اصطلاح الاتصال .&#x5B; **' &#x5D;</sup>

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


== طلبات التقييم ==
في حين أن [[ترتيب العمليات الحسابية|ترتيب العمليات]] يحدد [[شجرة نحو مجرد|شجرة بناء الجملة المجردة]] للتعبير، فإن ترتيب التقييم يحدد الترتيب الذي يتم به تقييم التعبيرات. مثل برنامج [[بايثون]]<syntaxhighlight lang="python">def f(x):
  print(x, end='')
  return x

print(f(1) + f(2),end='') </syntaxhighlight>المخرجات <code>123</code> بسبب ترتيب التقييم من اليسار إلى اليمين في بايثون، ولكن نفس البرنامج في [[لغة كامل الموضوعية|OCaml]]:<syntaxhighlight lang="ocaml">
let f x = print_int x; x ;;
print_int (f 1 + f 2) 
</syntaxhighlight>المخرجات <code>213</code> بسبب ترتيب تقييم OCaml من اليمين إلى اليسار.

يظهر ترتيب التقييم بشكل رئيسي في التعليمات البرمجية مع [[تأثير جانبي (علم الحاسوب)|آثار جانبية]]، ولكنه يؤثر أيضًا على أداء التعليمات البرمجية لأن الترتيب الصارم يمنع [[:en:Instruction scheduling|جدولة التعليمات]]. لهذا السبب، تركت معايير اللغة مثل C++ تقليديًا الترتيب غير محدد، على الرغم من أن لغات مثل Java وC# تحدد ترتيب التقييم من اليسار إلى اليمين  وقد أضاف معيار [[:en:C++17|C++ 17]] قيودًا على ترتيب التقييم.

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

تقوم Lisp و [[إيفل (لغة برمجة)|Eiffel]] وJava الشائعة بتقييم وسيطات الوظائف من اليسار إلى اليمين. C يترك الترتيب غير محدد. يتطلب المخطط أن يكون أمر التنفيذ هو التنفيذ المتسلسل لتبديل غير محدد للوسائط. وبالمثل، يترك [[لغة كامل الموضوعية|OCaml]] الترتيب غير محدد، ولكنه عمليًا يقوم بتقييم الوسائط من اليمين إلى اليسار نظرًا لتصميم [[آلة مجردة|آلته المجردة]] . كل هذه هي تقييم صارم.

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

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

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

== استراتيجيات ملزمة صارمة ==

=== اتصل حسب القيمة ===
في الاستدعاء بالقيمة (أو المرور بالقيمة)، يُربط قيمة التعبير المقدم كوسيط إلى المتغير المقابل في الدالة، عادةً عن طريق نسخ القيمة إلى منطقة ذاكرة جديدة. إذا كانت الدالة أو الإجراء قادرة على تعيين قيم لمعاملاتها، فإنها تعيين قيم فقط لمتغيرها المحلي، وبالتالي، أي شيء يتم تمريره إلى استدعاء الدالة يظل دون تغيير في نطاق النداء الأصلي بعد عودة الدالة. على سبيل المثال، في لغة باسكال، عند تمرير مصفوفة بالقيمة، سيؤدي ذلك إلى نسخ كامل المصفوفة، وأي تغييرات تطرأ على هذه المصفوفة ستكون غير مرئية للمتصل بالدالة بعد اكتمال تنفيذ الدالة.<syntaxhighlight lang="pascal">
program Main; 
uses crt;

procedure PrintArray(a: Array of integer);
var
 i: Integer;
begin
 for i := Low(a) to High(a) do
  Write(a[i]);
 WriteLn();
end;

Procedure Modify(Row : Array of integer); 
begin 
 PrintArray(Row); // 123
 Row[1] := 4;
 PrintArray(Row); // 143
end;

Var
 A : Array of integer; 
begin
 A := [1,2,3]؛
 PrintArray(A); // 123
 Modify(A);
 PrintArray(A); // 123
end.
</syntaxhighlight>

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

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

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

نظرًا للاختلاف في بناء الجملة، فإن الفرق بين الاتصال حسب المرجع (حيث يكون نوع المرجع ضمنيًا) والاتصال عن طريق المشاركة (حيث يكون نوع المرجع صريحًا) غالبًا ما يكون غير واضح للوهلة الأولى. اختبار بسيط هو ما إذا كان من الممكن كتابة وظيفة <code>swap(a, b)</code> في اللغة. على سبيل المثال في فورتران:<syntaxhighlight lang="fortran">
program Main
  implicit none 
  integer :: a = 1
  integer :: b = 2
  call Swap(a, b)
  print *, a, b ! 2 1
contains
  subroutine Swap(a, b)
    integer, intent(inout) :: a, b
    integer :: temp
    temp = a
    a = b
    b = temp
  end subroutine Swap
end program Main
</syntaxhighlight>ولذلك، فإن نية فورتران <code>inout</code> تنفذ الاستدعاء حسب المرجع؛ يمكن تحويل أي متغير ضمنيًا إلى مؤشر مرجعي. على النقيض من ذلك فإن أقرب ما يمكن الحصول عليه في Java هو:<syntaxhighlight lang="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
</syntaxhighlight>حيث يجب استخدام نوع <code>Box</code> صريح لتقديم المقبض. Java عبارة عن مكالمة من خلال المشاركة ولكنها ليست مكالمة حسب المرجع.

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

تتشابه دلالات الاستدعاء عن طريق استعادة النسخ في كثير من الحالات مع الاستدعاء حسب المرجع، ولكنها تختلف عندما تستعار وسيطتان دالتان أو أكثر لبعضهما البعض (أي الإشارة إلى نفس المتغير في بيئة المتصل). ضمن الاستدعاء حسب المرجع، ستؤثر الكتابة إلى وسيطة واحدة على الوسيطة الأخرى أثناء تنفيذ الوظيفة. في حالة الاستدعاء عن طريق استعادة النسخ، لن تؤثر الكتابة إلى وسيطة واحدة على الأخرى أثناء تنفيذ الوظيفة، ولكن في نهاية الاستدعاء، قد تختلف قيم الوسيطتين، وليس من الواضح أي وسيطة سيتم نسخها مرة أخرى أولاً وبالتالي ما هي القيمة التي يتلقاها متغير المتصل. على سبيل المثال، تحدد Ada أن تعيين النسخ لكل معلمة  أو  يحدث بترتيب عشوائي. من البرنامج التالي (غير قانوني في Ada 2012)  يمكن ملاحظة أن سلوك GNAT هو النسخ بالترتيب من اليسار إلى اليمين عند العودة:<syntaxhighlight lang="ada">
with Ada.Text_IO; use Ada.Text_IO;

procedure Test_Copy_Restore is
 procedure Modify (A, B : in out Integer) is
 begin
   A := A + 1;
   B := B + 2;
 end Modify;
 X : Integer := 0;
begin
 Modify(X, X);
 Put_Line("X = " & Integer'Image(X));
end Test_Copy_Restore;
-- $ gnatmake -gnatd.E test_copy_restore.adb; ./test_copy_restore
-- test_copy_restore.adb:12:10: warning: writable actual for "A" overlaps with actual for "B" [-gnatw.i]
-- X = 2
</syntaxhighlight>إذا أعاد البرنامج 1، فسيتم النسخ من اليمين إلى اليسار، وتحت دلالات الاستدعاء حسب المرجع، سيرجع البرنامج 3.

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

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

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

تمت ملاحظة هذه التقنية لأول مرة بواسطة [[باربارا لسكوف|باربرا ليسكوف]] في عام 1974 للغة [[نظام برمجة كلو|CLU]] . يتم استخدامه من قبل العديد من اللغات الحديثة مثل [[بايثون (لغة برمجة)|بايثون]] (القيم المشتركة تسمى "الكائنات")،  [[جافا (لغة برمجة)|جافا]] (الكائنات)، [[روبي (لغة برمجة)|روبي]] (الكائنات)، [[جافا سكريبت]] (الكائنات)، المخطط (هياكل البيانات مثل المتجهات)،  [[أبل سكريبت|AppleScript]] (القوائم والسجلات والتواريخ وكائنات البرنامج النصي)، وOCaml و [[أم أل (لغة برمجة)|ML]] (المراجع والسجلات والمصفوفات والكائنات وأنواع البيانات المركبة الأخرى)، [[ميبل (برنامج)|وMaple]] (الجداول والجداول)، و [[تي سي إل|Tcl]] (الكائنات). المصطلح "الاتصال عبر المشاركة" كما هو مستخدم في هذه المقالة ليس شائع الاستخدام؛ المصطلحات غير متناسقة عبر مصادر مختلفة. على سبيل المثال، في مجتمع Java، يقولون أن Java يتم استدعاؤها حسب القيمة.

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

على سبيل المثال، في لغة Python، تكون القوائم قابلة للتغيير ويتم تمريرها من خلال الاتصال بالمشاركة، لذلك:<syntaxhighlight lang="python">
def f(a_list): 
  a_list.append(1)

m = []
f(m)
print(m)
</syntaxhighlight>المخرجات <code>[1]</code> لأن طريقة <code>append</code> تعدل الكائن الذي يتم استدعاؤها عليه.

وفي المقابل، فإن التعيينات داخل الوظيفة ليست ملحوظة للمتصل. على سبيل المثال، يربط هذا الكود الوسيطة الرسمية بكائن جديد، لكنه غير مرئي للمتصل لأنه لا يغير  :<syntaxhighlight lang="python">
def f(a_list):
  a_list = a_list + [1] 
  print(a_list) # [1]

m = []
f(m)
print(m) # []
</syntaxhighlight>

=== الاتصال عن طريق العنوان ===
يعد **الاتصال حسب العنوان''' أو التمرير حسب العنوان أو الاتصال/التمرير بواسطة المؤشر طريقة تمرير معلمة حيث يتم تمرير عنوان الوسيطة كمعلمة رسمية. داخل الوظيفة، يمكن استخدام العنوان (المؤشر) للوصول إلى قيمة الوسيطة أو تعديلها. على سبيل المثال، يمكن تنفيذ عملية المبادلة على النحو التالي في C:
```c
#include <stdio.h>

void swap(int* a, int* b) {
  int temp = *a;
  *a = *b;
  *b = temp;
}

int main() {
  int a = 1;
  int b = 2;
  swap(&a, &b);
  printf("%d %d", a, b); // 2 1
  return 0;
}
```
يتعامل بعض المؤلفين مع `&` كجزء من بناء جملة استدعاء  . ضمن طريقة العرض هذه، تدعم لغة C استراتيجية تمرير معلمة الاستدعاء حسب المرجع. يتبنى مؤلفون آخرون وجهة نظر مختلفة مفادها أن التنفيذ المقدم  في لغة C هو مجرد محاكاة للاستدعاء حسب المرجع باستخدام المؤشرات. ضمن طريقة العرض "المحاكاة" هذه، فإن المتغيرات القابلة للتغيير في لغة C ليست من الدرجة الأولى (أي أن قيم l ليست تعبيرات)، بل هي أنواع المؤشر. في هذا العرض، يعد برنامج المبادلة المقدم عبارة عن سكر نحوي لبرنامج يستخدم المؤشرات طوال الوقت،  على سبيل المثال هذا البرنامج (تمت إضافة   لتسليط الضوء على أوجه التشابه مع برنامج Java  call-by-sharing أعلاه ):
```c
#include <stdio.h>

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

void assign(int *p, int v) {
  *p = v;
}

void swap(int* a, int* b) {
    int temp_storage; int* temp = &temp_storage;
    assign(temp, read(a));
    assign(a, read(b));
    assign(b, read(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;
}
```
نظرًا لأن  في هذا البرنامج تعمل على المؤشرات ولا يمكنها تغيير المؤشرات نفسها، ولكن فقط القيم التي تشير إليها المؤشرات، يرى هذا الرأي أن استراتيجية التقييم الرئيسية لـ C تشبه إلى حد كبير استراتيجية الاتصال بالمشاركة.

تعمل لغة C++ على إرباك المشكلة بشكل أكبر من خلال السماح بإعلان  واستخدامها مع بناء جملة "مرجعي" خفيف الوزن للغاية:
```c++
void swap(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. على هذا النحو، يعتبر العديد من المؤلفين أن المكالمة حسب العنوان هي استراتيجية تمرير معلمة فريدة تختلف عن المكالمة حسب القيمة، والمكالمة حسب المرجع، والمكالمة حسب المشاركة.

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

## استراتيجيات ملزمة غير صارمة

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

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

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

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

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

في تنفيذ R للاستدعاء حسب الحاجة، يتم تمرير كافة الوسائط، مما يعني أن R يسمح بتأثيرات جانبية عشوائية.

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

يعد تقليل الرسم البياني بمثابة تنفيذ فعال للتقييم البطيء.

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

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

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

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

الإستراتيجية غير حتمية، حيث أن التقييم يمكن أن يحدث في أي وقت بين خلق المستقبل (أي عندما يتم إعطاء التعبير) واستخدام قيمة المستقبل. الإستراتيجية غير صارمة لأن نص الوظيفة قد يُرجع قيمة قبل تقييم الوسائط. ومع ذلك، في معظم التطبيقات، قد يظل التنفيذ عالقًا في تقييم وسيطة غير ضرورية. على سبيل المثال، البرنامج
```haskell
f x = 1/x 
g y = 1
main = print (g (f 0))
```
قد يكون لديك  إنهاء قبل  ، والإخراج 1، أو قد يؤدي إلى خطأ بسبب التقييم  .

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

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

## أنظر أيضا

* شكل بيتا العادي
* مقارنة بين لغات البرمجة
* تقييم
* حساب التفاضل والتكامل لامدا
* قيمة المكالمة عن طريق الدفع
* التقييم الجزئي

## مراجع





## قراءة متعمقة

* 
* 
* 
* 
* 
* 

## روابط خارجية

* مصور هندسة التفاعل التفاعلي عبر الإنترنت، والذي يقوم بتنفيذ آلة تعتمد على الرسم البياني للعديد من استراتيجيات التقييم الشائعة.

تصنيف:إستراتيجية تثمين
تصنيف:برمجة
تصنيف:علوم حاسوبية
تصنيف:برمجيات
تصنيف:مشغلات (برمجة)
تصنيف:نظرية النمط