لغة كامل الموضوعية

الفلسفة

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

أمثلة على الشفرات

يمكن بكل سهولة دراسة قصاصات شفرة الأو كامل بإدخالها إلى "مستوى أعلى". وهذه هي جلسة أو كامل تفاعلية التي تطبع الأنماط الاستدلالية للتعبيرات الناتجة أو المحددة. يبدأ المستوى الأعلى من الأو كامل ببساطة عبر تنفيذ برنامج "أوكامل":
  $ ocaml
       Objective Caml version 3.09.0
  #
بعد ذلك يمكن إدخال الشفرة على الفور، على سبيل المثال لحساب 1+2*3:
  # 1 + 2 * 3;;
  - : int = 7
يستدل الأوكامل على نمط التعبير بكونه "int" (أي رقم صحيح دقيق ناتج عن الآلة) ويمنحنا الرقم "7"

هالو وورلد

البرنامج التالي "hello.ml":
يمكن تصنيفه إلى شفرة بايت قابلة للتنفيذ:
$ ocamlc hello.ml -o hello
أو تصنيفه إلى شفرة مصدرية مثالية قابلة للتنفيذ:
$ ocamlopt hello.ml -o hello
ثم يتم تنفيذها بالطريقة التالية:
$./hello
Hello world!
$

تلخيص قائمة مجموعة من الأعداد الصحيحة

القوائم هي أحد أنواع البيانات الرئيسية في الأو كامل. والمثال التالي للشفرة يحدد قيم دالة متكررة تقبل برهانا واحدا xs. وتتكرر الدالة عبر قائمة موجودة وتتيح لنا قيمة من عناصر الأرقام الصحيحة. بيان :التطابق Match" يعني وجود متشابهات: ومع عنصر التحول للغات السي بلس سي سي أو الجافا، بالرغم من أنه أمر أكثر عمومية.
let rec sum xs =
  match xs with
    [] -> 0
    | x :: xs' -> x + sum xs'
 # sum [1;2;3;4;5];;
 - : int = 15
وهناك طريقة أخرى تكون باستخدام دالة الطي القياسية التي تنجح مع القوائم:
let sum xs =
    List.fold_left (+) 0 xs
 # sum [1;2;3;4;5];;
 - : int = 15

كويكسورت Quicksort

تعير لغة أو كامل نفسها للتعبير الدقيق لعمليات حسابية متكررة. المثال التالي على أحد الشفرات يستعين بعمليات حسابية شبيهة بالكويك سورت أو التصنيف السريع الذي يقوم بتصنيف أحد القوائم بترتيب متزايد ومتسرع.
 let rec qsort = function
   | [] -> []
   | pivot :: rest ->
       let is_less x = x <pivot in
       let left, right = List.partition is_less rest in
       qsort left @ [pivot] @ qsort right

مفارقة عيد الميلاد

البرنامج التالي يقوم بحساب أصغر عدد من الأشخاص الموجودين في غرفة ما اولذين يكون احتمال تفرد يوم مولدهم بشكل كامل أقل من 50% (بما يسمى مفارقة عيد الميلاد حيث يكون الاحتمال بالنسبة لشخص واحد 100% بينما لشخصين 364/365... الخ) (الإجابة = 23).
 let year_size = 365.;;

 let rec birthday_paradox prob people =
     let prob' = (year_size -. float people) /. year_size *. prob  in
     if prob' <0.5 then
         Printf.printf "answer = %d\n" (people+1)
     else
         birthday_paradox prob' (people+1) ;;

 birthday_paradox 1.0 1

الأعداد الكنسية

الشفرة التالية تحدد تشفيرا للكنيسة وضعته للأعداد الطبيعية، مع عدد لاحق (succ) وعدد إضافي (add). الأعداد الكنسية هي دالة ذات مستوى أعلى تقبل الدالة f والقيمة x وتضيف f إلى x لعدد n من المرات. ولتحويل العدد الكنسي من قيمته الوظيفية إلى سلسلة معلومة نقوم بإدخاله على دالة تدخل السلسلة s إلى مدخلاتها والتسلسل الثابت " 0
let zero f x = xlet succ n f x = f (n f x)let one = succ zerolet two = succ (succ zero)let add n1 n2 f x = n1 f (n2 f x)let to_string n = n (fun k -> "S" ^ k) "0"let _ = to_string (add (succ two) two)

الدالة العاملية دقيقة التحكم (المكتبات)

يمكن الوصول بشكل مباشر إلى مجموعة متنوعة من المكتبات من أوكامل. على سبيل المثال، تحتوي أو كامل على مكتبة مؤسسة بداخلها للعمليات الرياضية الدقيقة في التحكم. ونظرا لأن الدوال العاملية تتزايد بسرعة كبيرة، فهي سرعان ما تغمر الأعداد الدقيقة آليا (عادة 32 أو 64 بايت). ومن ثم فإن التحويل إلى عوامل أمر مناسب للعمليات الرياضية الدقيقة تحكميا.
في الأوكامل تتيح وحدة num عمليات حسابية دقيقة تحكميا ويمكن تحميلها إلى مستوى أعلى عامل باستخدام:
# #load "nums.cma";;# open Num;;
يمكن بعد ذلك كتابة الدالة العاملية باستخدام عمليات عددية دقيقة تحكميا =/,*/ و-/:
# let rec fact n =
    if n =/ Int 0 then Int 1 else n */ fact(n -/ Int 1);;val fact : Num.num -> Num.num = <fun>
ويمكن للدالة أن تقوم بحساب عوامل أكبر مثل 120!:
# string_of_num (fact (Int 120));;- : string ="6689502913449127057588118054090372586752746333138029810295671352301633557244962989366874165271984981308157637893214090552534408589408121859898481114389650005964960521256960000000000000000000000000000"
تركيب الجمل المرهق بالنسبة لعمليات Num يمكن التخفيف منه وذلك بفضل الامتداد "كامل بي فور سينتاكس" الذي يسمى الحمل الزائد المعين Delimited Overloafing:
# #require "pa_do.num";;# let rec fact n = Num.(if n = 0 then 1 else n * fact(n-1));;val fact : Num.num -> Num.num = <fun># fact Num.(120);;- : Num.num =
  <num 668950291344912705758811805409037258675274633313802981029567
  135230163355724496298936687416527198498130815763789321409055253440
  8589408121859898481114389650005964960521256960000000000000000000000000000>

المثلث (جرافيك)

البرنامج التالي "simple.ml" يقوم بتصميم مثلث دوار ثنائي الأبعاد باستخدام أوبن جل:
 let () =
   ignore(Glut.init Sys.argv);
   Glut.initDisplayMode ~double_buffer:true ();
   ignore (Glut.createWindow ~title:"OpenGL Demo");
   let angle t = 10. *. t *. t in
   let render () =
     GlClear.clear [ `color ];
     GlMat.load_identity ();
     GlMat.rotate ~angle: (angle (Sys.time ())) ~z:1. ();
     GlDraw.begins `triangles;
     List.iter GlDraw.vertex2 [-1., -1.; 0., 1.; 1., -1.];
     GlDraw.ends ();
     Glut.swapBuffers () in
   GlMat.mode `modelview;
   Glut.displayFunc ~cb:render;
   Glut.idleFunc ~cb:(Some Glut.postRedisplay);
   Glut.mainLoop ()
ويحتاج ذلك إلى روابط تربط بين لابل جل وأوبن جل. يمكن بعد ذلك تصنيف البرنامج إلى شفرة بايت باستخدام:
  $ ocamlc -I +lablGL lablglut.cma lablgl.cma simple.ml -o simple
أو إلى شفرة مصدرية:
  $ ocamlopt -I +lablGL lablglut.cmxa lablgl.cmxa simple.ml -o simple
ثم التنفيذ:
  $./simple
وهو برنامج جرافيك ثنائي وثلاثي الأبعاد أكثر تطورا وتعقيدا وعالي الأداء تم تطويره بسهولة في الأو كامل. وبفضل استخدام أوبن جل فإن البرامج الناتجة لا تكون فقط بليغة وعلى قدر من الكفاءة ولكنها تكون أيضا ذات منصة تبادلية مصنفة دون أي تغير في كافة المنصات الرئيسية.

تسلسل فيبوناتشي

الشفرة التالية تستطيع حساب تسلسل فيبوناتشي لعدد تم إدخاله نشير إليه ب " ن "، وهو يستعين بالتكرار للاحقة والتوافق النمطي:

 
let rec fib_aux n a b =
  match n with
  | 0 -> a
  | _ -> fib_aux (n - 1) (a + b) a;;let fib n = fib_aux n 0 1;;
من المحتمل أكثر كتابتها:  
let fib n =
  let rec fib_aux n a b =
    match n with
    | 0 -> a
    | _ -> fib_aux (n - 1) (a + b) a
  in
  fib_aux n 0 1;;

ميتا أو كامل

ميتا أو كامل  هو امتدادا لبرمجية متعددة الاستخدامات من أوكامل تمكن من التصنيف الإضافي لشفرات آلات جديدة خلال وقت التشغيل. وتحت ظروف معينة يمكن حدوث بعض التسارع الواضح باستخدام البرمجة متعددة المراحل نظرا لتوافر المزيد من المعلومات التفصيلية حول البيانات التي ينبغي معالجتها في وقت التشغيل أكثر من تلك في وقت التصنيف المعتاد، لذلك يمكن للمصنف الإضافي التخلص من الكثير من حالات تفقد الظروف... الخ.
فعلى سبيل المثال: إذا كان من المعروف أنه في وقت التصنيف يكون من المطلوب وجود دالة قوة محددة x -> x^n باستمرار، ولكن القيمة "ن " معلومة وقت في وقت التشغيل، فبإمكانك استخدام دالة قوة ذات مرحلتين في الميتا أوكامل:
 let rec power n x =
   if n = 0
   then.<1>.
   else
     if even n
     then sqr (power (n/2) x)
     else.<.~x *. ~(power (n-1) x)>.
وبمجرد أن تعلم قيمة " ن" وقت التشغيل يمكنك أن تتولد دالة قوة سريعة للغاية ومتخصصة أيضا:
.<fun x ->.~(power 5.<x>.)>.
فتكون النتيجة:
 fun x_1 -> (x_1 *
     let y_3 = 
         let y_2 = (x_1 * 1)
         in (y_2 * y_2)
     in (y_3 * y_3))
ويتم جمع الدالة الجديدة تلقائيا: