بسم الله الرحمن الرحيم
هذا الدرس الرابع من تلخيص كتاب الساحر، الذي قد بدأناه وهذه مقدمته:
الإجراء المركب
الإجراء المركب ليس إلا إجراء مكوَّن من أكثر من إجراء، أي أنه يحوي إجراء داخله. وقد اتفقنا في دروسنا الأولى أن نسمي الإجراء وظيفة ولا حرج، فهما شيء واحد.
نضرب لك مثالا لتفهم. هذه ثلاث وظائف Procedures سنركب منها وظيفة واحدة جامعة. الوظيفة الأولى لتربيع العدد، والثانية لجمع مربع عددين، والثالثة تؤدي ما تؤديه الثانية لكنها تضيف إلى أول مدخل الرقم واحد، أما الثاني فتضربه في اثنين قبل تربيعه.
الوظيفة (أو قل الإجراء، تعبتُ من التكرار:) ) الأولى: تربع العدد:
(define (square number) (* number number))
الوظيفة الثانية: تجمع مربع عددين:
(define (sum-of-two-squares first second)
(+ (square first) (square second)))
الوظيفة الأخيرة: تؤدي وظيفة الثانية لكن تزيد واحدًا على المدخل الأول قبل تربيعه، وتضرب المدخل الثاني في اثنين قبل تربيعه:
(define (my_function number)
(sum-of-two-squares (+ number 1) (* number 2)))
وأظنك لحظت أمرًا، أننا نكتب وظيفة ثم نستعملها داخل وظيفة أخرى، الوظيفة الأولى مستعملة في الثانية، والوظيفة الثانية مستعملة في الثالثة، وهذا ما يقصده الكاتب بالإجراء المركب.
والآن ننتقل سريعًا إلى وحدة التعويض المذكورة في الصفحة رقم ١٨.
وحدة التعويض substitute model
في الدرس السابق، وهذا رابطه (الساحر، الدرس الثالث، العَودية وكيف تُنَفَّذ التجميعة)، رأينا كيف تنفذ التجميعة، ولم نتعرض لكيف تنفذ الوظيفة، ومقال اليوم عن ذلك، لأن فيه إضافة.
النهج المتبع في تنفيذ الوظيفة يشبه النهج نفسه عند تنفيذ التركيبة، راجع الدرس السابق. لتنفيذ وظيفة تعالج بعض المدخلات فالقاعدة (قد نضيف إليها ونعدل ولا إشكال):
> نفذ متن الوظيفة ولا تنس تعويض كل موسط parameter في متنها بقيمته.
لنطبق القاعدة على الوظيفة الثالثة حتى يتضح لك الأمر:
(define (my_function number)
(sum-of-two-squares (+ number 1) (* number 2)))
هذه الوظيفة لها موسط parameter واحد وهو (number)، والقاعدة تقول لتنفيذ الوظيفة نفذ متنها مع تعويض كل موسط داخل المتن بقيمته.
ونقصده (بقيمته) = ما نمرره للوظيفة عند استدعائها، فلو استدعينا الوظيفة ومررنا لها الرقم ٣، فإن الموسط (number) داخل متن الوظيفة سيعوضه المُفَسِّر بالرقم ٣.
سنستدعي الوظيفة ونمرر لها الرقم ٣ ونتبع خطوات تنفيذها لتفهم:
(my_function 3)
لما نستدعي الوظيفة فالمُفَسِّر سينفذ متن الوظيفة، وسيعوض الموسط (number) بقيمته التي هي ٣، ومتن الوظيفة بعد تعويض الموسط بقيمته ستكون هكذا:
(sum-of-two-squares (+ 3 1) (* 3 2))
موسطات الوظيفة هاهنا تعبير، لذا سننفذ التعبير كما تعلمنا في الدرس السابق، التعبير الأول سيرجع ٤، زدنا وحدا على الموسط، والتعبير الثاني سيرجع ٦، ضرب الموسط في اثنين. ستكون الوظيفة:
(sum-of-two-squares 4 6)
ومتن الوظيفة هذا مكوَّن من وظيفة اسمها (sum-of-two-squares)، وهذه الوظيفة متنها:
(+ (square first) (square second)))
وبعد تعويض قيمة الموسطات:
(+ (square 4) (square 6))
وكما ترى، فهنا وظيفة أخرى اسمها (square)، سنعوض اسم الوظيفة هنا بمتنها وستصبح:
(+ (* 4 4) (* 6 6))
سننفذ التعبيرين وسيصبح متنها:
(+ 16 36)
والنتيجة النهائية ٥٢.
مررنا بالتفصيل الممل ورأينا خطوات سير عملية التنفيذ، وكل ما رأيته اسمه وحدة التعويض Substitute Model، والغرض من تقديمها تسهيل فهم كيف تطبق الوظيفة لا أن نبيَّن لك النهج الذي يتبعه المُفَسِّر، ليس هذا مقامه، فتفصيله في الباب الثالث والرابع من الكتاب.
طريقي تنفيذ
ومما لا بد من ذكره قبل الختام أن المؤلف ذكر طريقتين في التنفيذ، أولها اسمه التنفيذ الكسول، والثاني اسمه التنفيذ العادي. ودونك شرح موجز لهما:
التنفيذ الكسول
قد يسميه بعضهم بالتنفيذ الكسول Lazy Evaluation، أو الاستدعاء بالاسم call-by-name، والكتاب سماه Normal-Order Evaluation.
هذا النوع لا ينفذ الموسطات Parameters حتى يُحتَاج إليها في متن الوظيفة، بمعنى أن الوظيفة قد تنفذ دون تنفيذ الموسطات، وتنفيذ الموسطات يكون عند الحاجة.
مثلا لو كان أحد الموسطات في الوظيفة (WoW) تعبير لضرب عددين:
(Wow(* First Second))
ومتن الوظيفة لم يستعمل هذا الموسط/المدخل = فلن يُنفَّذ أبدًا.
التنفيذ العادي
قد يسميه بعضهم التنفيذ العادي وبعضهم الاستدعاء بالقيمة call-by-value، والكتاب سماه Applicative-Order Evaluation. وهذا النوع ينفذ الموسطات قبل تنفيذ الوظيفة، فلو مررت إليه بعض المدخلات فإنها سيعالجها إن كانت تحتاج المعالجة، مثلا كانت تعبيرًا، وبعد تنفيذها ستمررها إلى الوظيفة، لكنها ستصل منفذة جاهزة.
المثال الآتي:
(define (square number) (* number number))
(square (+ 1 3))
التعبير (3 1 +) سينفذ أولًا، ونتيجته ٤، ثم سيمرر إلى الوظيفة:
(square 4)
وبعد الانتهاء من تنفيذ الموسطات ستُنَفَّذ الوظيفة، متنها.
الخاتمة
وها أنا أخط بقلمي الخطوط الأخيرة لهذا المقال الشائق!
وفي نهاية الأمر لا يسعني سوى أن أشكرك على حسن قراءتك لهذا المقال، وأني لبشر أصيب وأخطِئ، فإن وفِّقت في طرح الموضوع فمن اللّٰه عز وجل وإن أخفقت فمن نفسي والشيطان.
أرجو منك تقييم كفاءة المعلومات من أجل تزويدي بالملاحظات والنقد البناء في خانة التعليقات أو عبر حساب الموقع، والسلام عليكم ورحمة اللّٰه تعالى وبركاته.