سؤال

أنا جديد على OCAML ومحاولة كتابة وظيفة نمط تمرير استمرار ، لكنني مرتبك تمامًا ما هي القيمة التي أحتاجها للانتقال إلى حجة إضافية على K

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

هكذا مثل

let rec even list = .... 

على CPS ، أعلم أنني بحاجة إلى إضافة وسيطة واحدة لتمرير الوظيفة مثل

let rec evenk list k = .... 

لكن ليس لدي أدنى فكرة عن كيفية التعامل مع هذا K وكيف يعمل هذا بالضبط

على سبيل المثال لهذه الوظيفة حتى ، تبدو البيئة

val evenk : int list -> (bool -> ’a) -> ’a = <fun>

evenk [4; 2; 12; 5; 6] (fun x -> x)  (* output should give false *)
هل كانت مفيدة؟

المحلول

الإستمرار k هي وظيفة تأخذ النتيجة من evenk ويؤدي "بقية الحساب" وينتج "الإجابة". ما هو نوع الإجابة وما تعنيه بـ "بقية الحساب" يعتمد على ما تستخدمه CPS إلى عن على. CPS عمومًا ليس غاية في حد ذاته ولكن يتم القيام به مع مراعاة بعض الأغراض. على سبيل المثال ، في شكل CPS ، من السهل جدًا تنفيذ مشغلي التحكم أو لتحسين مكالمات الذيل. دون معرفة ما تحاول إنجازه ، من الصعب الإجابة على سؤالك.

لما يستحق الأمر ، إذا كنت تحاول ببساطة التحويل من النمط المباشر إلى نمط التماس المستمر ، وكل ما تهتم به هو قيمة الإجابة ، وتمرير وظيفة الهوية لأن الاستمرار هو الصحيح.

الخطوة التالية الجيدة هي التنفيذ evenk باستخدام CPS. سأفعل مثالًا أبسط. إذا كان لدي وظيفة على الطراز المباشر

let muladd x i n = x + i * n

وإذا افترضت Primitives CPS mulk و addk, ، أستطيع أن أكتب

let muladdk x i n k =
  let k' product = addk x product k in
  mulk i n k'

وسترى أن mulptiplication يتم أولاً ، ثم "يستمر" k', الذي يفعل الإضافة ، وأخيرا ذلك continues مع k, الذي يعود إلى المتصل. الفكرة الرئيسية هي أنه داخل الجسم muladdk لقد خصصت استمرارًا جديدًا k' الذي يقف لنقطة وسيطة في وظيفة مضاعفة مضاعفة. لجعل الخاص بك evenk العمل عليك تخصيص واحد على الأقل من هذا القبيل.

آمل أن يساعد هذا.

نصائح أخرى

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

let rec even list return =
  if List.length list = 0
    then return true
    else if List.hd list mod 2 = 1
      then return false
      else even (List.tl list) return;;

let id = fun x -> x;;

مثال الاستخدام: "حتى [2 ؛ 4 ؛ 6 ؛ 8] id ؛؛".

بما أن لديك الاحتجاج evenk صحيح (مع وظيفة الهوية-تحويل بشكل فعال على نمط التمرير إلى النمط الطبيعي) ، أفترض أن الصعوبة في تحديد evenk.

k هي وظيفة الاستمرار التي تمثل بقية الحساب وإنتاج قيمة نهائية ، كما قال نورمان. لذا ، ما عليك فعله هو حساب نتيجة v من even وتمرير تلك النتيجة إلى k, ، عودة k v افضل من مجرد v.

تريد أن تعطي كمدخلات نتيجة وظيفتك كما لو لم تتم كتابتها بأسلوب تمرير استمرار.

فيما يلي وظيفتك التي تختبر ما إذا كانت القائمة تحتوي على أعداد صحيحة فقط:

(* val even_list : int list -> bool *)
let even_list input = List.for_all (fun x -> x mod 2=0) input

الآن دعنا نكتبها باستمرار cont:

(* val evenk : int list -> (bool -> 'a) -> 'a *)
let evenk input cont =
  let result = even_list input in
  (cont result)

يمكنك حساب النتيجة وظيفتك ، وتمرير resultإلى الاستمرار ...

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