الاثنين، 31 ديسمبر 2012
السبت، 29 ديسمبر 2012
الخميس، 27 ديسمبر 2012
الأحد، 23 ديسمبر 2012
حين تتحقق خطط المدى البعيد
حين كنت أعمل في صنع لغة كلمات سنة 2010 كانت هناك بعض القرارات التي اتخذتها في تصميم وتنفيذ اللغة. بعض هذه القرارات قد بدأت تظهر آثاره الآن!
الخميس، 20 ديسمبر 2012
الأحد، 16 ديسمبر 2012
رسم الصيغ الرياضية بلغة كلمات (الجزء الثاني)
الهدف من المشروع هو برنامج يرسم الصيغ الرياضية، مثلاً يقول له المستخدمم س^2 + 5 فيرسم البرنامج شكل الـparabola المعروف.
- في الجزء الأول تحدثنا عن الإعراب، الدالة التي تأخذ نصاً مثل 12+13 وتعود بالمصفوفة ["+"، 12، 13] التي تمثل ما يسمى بشجرة الإعراب parse tree.
لو كنت قد قرأت الجزء الأول فأنت إذاً جاهز الآن لنختتم هذه السلسلة.
حساب قيمة التعبير
حسناً. لدينا الآن شجرة إعراب مثل 100 أو ["+"، س، 12]، ماذا نفعل بها؟ نريد دالة اسمها تقييم تأخذ الشجرة وتعود بالقيمة التي تعبر عنها.
- لو كانت "الشجرة" في صورة قيمة عددية، نعود بتلك القيمة.
- لو كانت الشجرة هي المتغير س (كقيمة نصية)، فإننا لا نستطيع أن نفعل شيئاً بأنفسنا، لذلك سوف نقدم عاملاً إضافياً parameter للدالة تقييم به قيمة س المطلوبة.
- لو كانت الشجرة في صورة مصفوفة مثل ["+"، أ، ب] سوف نقوم بالآتي:
- ناد الدالة تقييم مع الفرع الأيمن أ لحساب قيمته
- ناد الدالة أيضاً مع الفرع الأيسر ب
- نفذ العملية الحسابية وارجع بالنتيجة.
كل هذا يعطينا الكود التالية، الدالة تأخذ الشجرة "ت" وقيمة "س" المحددة من البرنامج، وتحسب قيمة الصيغة الرياضية:
دالة تقييم (ت، س): إذا ت ~ ["+"، ؟أ، ؟ب]: ارجع ب: تقييم (أ، س)+ تقييم (ب، س) وإلا إذا ت ~ ["-"، ؟أ، ؟ب]: ارجع ب: تقييم (أ، س)- تقييم (ب، س) وإلا إذا ت ~ ["×"، ؟أ، ؟ب]: ارجع ب: تقييم (أ، س)× تقييم (ب، س) وإلا إذا ت ~ ["÷"، ؟أ، ؟ب]: مقام = تقييم (ب، س) إذا مقام <> 0 : ارجع ب: تقييم (أ، س)÷ مقام وإلا : اطبع "خطأ: قسمة على صفر" ارجع ب: 0 تم وإلا إذا ت ~ ["^"، ؟أ، ؟ب]: ارجع ب: أس (تقييم (أ، س)، تقييم (ب، س)) وإلا إذا ت ~ "س" : ارجع ب: س وإلا : -- لو وصلنا إلى هنا فقيمة ت هي اصلا عدد ارجع ب: ت تم نهاية
لاحظ كيف استخدمنا مرة أخرى عملية المطابقة ~ لتسهيل الموضوع. الآن نحن جاهزون للرسم. أولاً نكتب إجراءاً مساعداً يرسم المحاور س، ص
إجراء ارسم.المحاور (): ارسم.خط (400، 0)- (400، 599) ارسم.خط (0، 300)- (799، 300) نهاية
الآن سوف نكتب الدالة التي ترسم فعلاً. خطتنا كالآتي:
الدالة سوف تأخذ عاملين: من.س و إلى.س، لكي نستطيع أن نقول مثلاً ارسم س^2 من س=-4 إلى س=4
سوف تقوم الدالة بالآتي:
- كرر بحيث يبدأ المتغير أ بالقيمة من.س وينتهي بالقيمة إلى.س، وكل مرة نضيف قيمة صغيرة إلى أ:
- احسب ص عن طريق استدعاء تقييم لحساب قيمة الصيغة الرياضية، واعطها قيمة المتغير س تساوي العداد أ
- سوف نرسم خطاً صغيراً بين كل نقطتين:
- لو كان هذا أول تكرار، فلا يوجد لدينا سوى نقطة واحدة. خزن قيمة أ في المتغير أ.قديم وقيمة ص في المتغير ص.قديم
- لو لم يكن أول تكرار، فنحن لدينا النقطة (أ، ص) والنقطة (أ.قديم، ص.قديم). سنرسم خطاً بينهما
هذا يعطينا الكود :
إجراء ارسم.الدالة (التعبير، من.س، إلى.س): أ = من.س أ.قديم = لاشيء ص.قديم = لاشيء مقياس.س = 20 مقياس.ص = 15 كرر مادام أ <= إلى.س : ص = تقييم (التعبير، أ) إذا ليس أ.قديم = لاشيء : س1 = - أ × مقياس.س + 400 ص1 = - ص × مقياس.ص + 300 س2 = - أ.قديم × مقياس.س + 400 ص2 = - ص.قديم × مقياس.ص + 300 ارسم.خط (س1، ص1)- (س2، ص2)، 4 تم أ.قديم = أ ص.قديم = ص أ = أ + 0.1 انتظر (30) تابع نهاية
لاحظ أننا نضرب الإحداثيات في بعض الثوابت ليكون لدينا مقياس رسم، وننتظر 30 مليثانية بين كل رسمة لكي نرى الدالة وهي تُرسم بسلاسة على الشاشة. لاحظ أن هذه الطريقة تفترض بعض الخصائص للدالة المطلوب رسمها (مثلاً أنها متصلة continuous).
لا يبقى إلا ان نربط كل المكونات ببعضها!
اقرأ "الصيغة؟"، الصيغة اقرأ "من؟"، # أ اقرأ "إلى؟"، # ب الصيغة = تبديل (الصيغة، " "، "") الشجرة = تعبير (الصيغة) ارسم.المحاور () ارسم.الدالة (الشجرة، أ، ب)
ماذا فعلنا؟
- قرأنا الصيغة من المستخدم (وقيم س التي سنبدأ وننتهي بها)
- حذفنا المسافات من الصيغة
- أعربناها لنحصل على شجرة الإعراب بواسطة الدالة تعبير
- رسمنا المحاور
- نادينا ارسم.الدالة وأعطيناها الشجرة وقيم من.س وإلى.س
- ارسم.الدالة سوف تنادي تقييم باستمرار لكي تحسب قيمة الصيغة عند كل قيمة لـ س
- ....وترسم الخطوط المطلوبة!
كم سطراً كتبنا؟ للأسف تجاوزنا حاجز المائة قليلاً: 109. لكن لو حذفنا السطور الفارغة بين تعريفات الدوال...الخ سيكون العدد أقل من المائة.
أقل من مائة سطر، تقوم بما قد يحتاج مئات الأسطر في لغات أخرى...
يمكنك عزيزي القاريء أن تجرب عمل نسخة متقدمة من البرنامج تضيف إمكانية استخدام الدوال مثل جتا، جا، أو تضيف الثابتين ط (π) و هـ (e) أوتقدم بعض المساعدة للمستخدم. لمَ لا تجرب؟ :)
رسم الصيغ الرياضية بلغة كلمات
نريد برنامجاً يأخذ صيغة رياضية ويرسمها!
وإمعاناً في التحدي، نريد أن نكتب هذا البرنامج في مائة سطر من الكود أو أقل. هل سنقدر يا ترى؟ أعتقد أنك ستستمتع كثيراً بهذا المقال عزيزي القاري.
هذه الرسمة اسمها "شجرة الإعراب" أو parse tree، وهي تشبه الشجرة لأن لها جذراً وفروعاً. كيف نعبر عن هذه الشجرة بقيمة في لغة كلمات؟ هناك طرق كثيرة: يمكن أن نستخدم الفصائل والكائنات، أو المصفوفات، أو القواميس...فلنستخدم طريقة بسيطة: سوف تكون كل شجرة عبارة من مصفوفة من ثلاثة عناصر: العملية الحسابية نفسها، والقيمتان التي تجري عليهما العملية. مثلاً إن قمنا بإعراب التعبير "4+5" سوف نحصل على المصفوفة ["+"، 4، 5]. لو أعربنا القيمة النصية "(4+5)×2" سوف نحصل على ["×"، ["+"، 4، 5]، 2]. أي أن الشجرة هي عملية ضرب بين ["+"، 4، 5] وبين 2.
لو افترضنا أننا - بطريقة ما - لدينا دالة تأخذ نصاً من المستخدم وتعود لنا بهذه الشجرة، فإنه من السهل أن نحسب القيمة المطلوبة من الشجرة: نحسب الفرع الأيمن، ثم نحسب الفرع الأيسر، ثم نقوم بتطبيق العملية الحسابية.
لاحظ أن الإعراب لا يعود دائماً بمصفوفات..لو أعربنا مثلاً التعبير 12 فإن "الشجرة" ما هي إلا العدد 12 نفسه.
رائع. الآن علينا أن نفكر: مم تتكون الصيغ الرياضية؟ سوف نسمي الصيغة في صورتها النهائية "تعبير حسابي"، وهذا التعبير مكون من حد واحد أو أكثر. ما الذي يفصل بين الحدود في التعبير الواحد؟ علامات الجمع والطرح. أي أن التعبير يكون في صيغة حد1 + حد2 - حد3....الخ، أو مكون من حد واحد.
في السطر الأخير نجرب القواعد الجديدة. سوف يطبع مفسر كلمات لك القيمة......لاشيء :(
لماذا؟ في الواقع سوف تقوم كلمات بإعراب التعبير، لكننا لم نطلب منها أن تعطينا شجرة إعراب، لذلك سوف تعود لنا بالقيمة لاشيء. هيا نغير ذلك الموقف! فلنبدأ بشيء بسيط كالأرقام:
لاحظ شيئين:
في السطر الأول قلنا خانة:أ رقم:ب ، هذه طريقتنا في إعطاء أسماء للمكونات التي نعربها.
أننا قلنا في أخر السطر => أ + ب ، وهذه طريقتنا في أن نعود بقيم أثناء الإعراب
يمكن أن نقرأ السطر كله كالآتي: الرقم مكون من خانة هي أ، ورقم أصغر هو ب، وحين نجدهما نعود بالقيمة أ + ب.
لاحظ أن أ و ب هما نصان، فلو أعربنا الرقم "123" فسيكون أ = "1" و ب يساوي "23" (الأرقام تقرأ من اليسار) وبهذا يكون الرقم كله هو أ + ب = "123"
ماذا عن السطر الثاني الذي يقول أو خانة؟ نحن لم نخبره بأي قيمة يعود، لكن لو رأى مفسر كلمات قاعدة ما هي الا استدعاء قاعدة أخرى (نحن لم نفعل سوى استدعاء "خانة") فسيعود بنفس القيمة الآتية من القاعدة المستدعاه. كأني بالضبط قلت أو خانة:أ => أ
ماذا عن السطر خانة = من "0" إلى "9"؟ حين تكون القاعدة ما هي إلا قيمة نصية فالقيمة العائدة منها هي نفس القيمة النصية.
إذاً قد عرفنا ماذا يرجع من رقم. ماذا عن شيء مثل تعبير؟
باللغة البشرية:
التعبير هو حد اسمه أ، ثم علامة "+"، ثم تعبير أصغر اسمه ب ، وفي تلك الحالة ارجع بالمصفوفة ["+"، أ، ب]
أو هو حد اسمه أ، ثم علامة "-"، ثم تعبير أصغر اسمه ب، وهنا ارجع بالمصفوفة ["-"، أ، ب]
أو هو مجرد حد اسمه أ، وفي تلك الحالة ارجع بذلك الحد.
سهل، أليس كذلك؟ بنفس الطريقة نعدل "حد" و "أس" و"أولي" ليكون لدينا القواعد كلها:
لاحظ أننا في هذا الجزء التالي قد حولنا الرقم من قيمة نصية إلى قيمة عددية:
سوف تصنع لنا كلمات دالة اسمها "تعبير" (لأننا قد سمينا القواعد "تعبير")، وهذه الدالة إن أعطيناها نصاً فستعطينا شجرة إعراب. جرب أن تضيف هذا السطر في آخر البرنامج:
اطبع تعبير("12+13×14")
سوف يظهر المخرج التالي:
["+"، 12، ["×"، 13، 14]]
في الواقع الكود السابقة ليست دقيقة لأن العمليات الرياضية + - ÷ × بها خاصية left associativity. أي أن تعبير مثل 1-2-5 المفروض أن يكون (1-2)-5، لكن برنامجنا يعتبره 1-(2-5)، أي أنه يعود بالشجرة ["-"، 1، ["-"، 2، 5] بدلاً من الشجرة الصحيحة وهي ["-"، ["-"، 1، 2]، 5]
سبب المشكلة هو أنه كان المفروض في القواعد أن نقول:
تعبير = تعبير + حد
ولكننا قلنا
تعبير = حد + تعبير
للأسف لا يمكن استخدام الطريقة الصحيحة في هذا الإصدار من كلمات بسبب مشكلة اسمها left recursion (هناك طرق لحل تلك المشكلة لكنها لم تطبق في كلمات بعد). لذلك علينا الحذر: البرنامج سيعطي نتائجاً خاطئة في المدخلات أ-ب-ج أو أ÷ب÷ج، ولكن يمكننا استخدام الأقواس في تلك الحالات.
على العموم قد أنهينا جزء إعراب الصيغ الرياضية، ومازال لدينا 70 سطراً أيضاً!
وإمعاناً في التحدي، نريد أن نكتب هذا البرنامج في مائة سطر من الكود أو أقل. هل سنقدر يا ترى؟ أعتقد أنك ستستمتع كثيراً بهذا المقال عزيزي القاري.
الجزء الأول: كيف نفهم الصيغة الرياضية؟
يوجد في علوم الحاسب ما يسمى parsing (الإعراب). لو أعربنا التعبير الحسابي س^2+5 فسيكون لنا النتيجة التالية:
لو افترضنا أننا - بطريقة ما - لدينا دالة تأخذ نصاً من المستخدم وتعود لنا بهذه الشجرة، فإنه من السهل أن نحسب القيمة المطلوبة من الشجرة: نحسب الفرع الأيمن، ثم نحسب الفرع الأيسر، ثم نقوم بتطبيق العملية الحسابية.
لاحظ أن الإعراب لا يعود دائماً بمصفوفات..لو أعربنا مثلاً التعبير 12 فإن "الشجرة" ما هي إلا العدد 12 نفسه.
رائع. الآن علينا أن نفكر: مم تتكون الصيغ الرياضية؟ سوف نسمي الصيغة في صورتها النهائية "تعبير حسابي"، وهذا التعبير مكون من حد واحد أو أكثر. ما الذي يفصل بين الحدود في التعبير الواحد؟ علامات الجمع والطرح. أي أن التعبير يكون في صيغة حد1 + حد2 - حد3....الخ، أو مكون من حد واحد.
كيف نعبر عن هذا رياضياً؟ هناك طريقة اسمها Parse Expression Grammar أو PEG تسمح لنا أن نكتب القاعدة بهذه الطريقة:
تعبير = حد "+" تعبير (هذه قاعدة 1#)
أو حد "-" تعبير (قاعدة 2#)
أو حد (قاعدة 3#)
ما معنى هذا الوصف؟ معناه أن التعبير يمكن أن يكون حداً واحداً أو مجموعة من الحدود يفصل بينها + و -. مثلاً يمكن أن نبدأ بالحد "2×3". نحن نعرف أن هذا تعبير من قاعدة #3 من التعريف. ماذا عن 1 + 2×3؟ نعرف أن هذا أيضاً تعبير (من قاعدة #1 التي تقول أن حد + تعبير = تعبير، وبالتالي سمحت لنا بإضافة حد في المقدمة). ماذا عن 5 - 1 + 2×3؟ هذا أيضاً تعبير من جزء 2# من التعريف
لو شعرت أن الأمر صعب فلا تقلق: الموضوع ببساطة هو recursion مثلما تعلمت في البرمجة. المسألة هي أن التعبير يمكن أن يكون حداً أو يكون حد + حد + حد ....، أو حد + حد - حد - حد ....الخ.
ماذا عن الحدود نفسها؟ الحد هو "أس" واحد أو أكثر تفصل بينها علامات ×، ÷
هذه كلها حدود:
5^2 × 6
6 ÷ 3
18
6^س
كيف نكتبها بطريقة PEG؟ هكذا:
حد = أس "×" حد
أو أس "÷" حد
أو أس
وهي كما ترى نفس طريقة التعبيرات. لاحظ أن قيمة عادية مثل "18" نعتبرها أس رغم غياب علامة ^، مثلما اعتبرنا أن 12 هو تعبير رغم غياب علامة + أو -
ماذا عن الأسس؟ هي ببساطة مجموعة من واحد أو أكثر من التعبيرات الأولية يفصل بينها علامة ^. كل هذه أسس:
س^2
2^س
س^2^3
س
12
والقاعدة (كما خمنت) هي:
أس = أولي "^" أس
أو أولي
ولكن ما هو التعبير الأولي؟؟؟ إنه رقم، أو المتغير س، أو تعبير بين أقواس:
أولي = "س"
أو رقم
أو "(" تعبير ")"
لم يبق ما نعرّفه سوى الأرقام نفسها. الرقم هو خانة واحدة أو أكثر (الخانة هي الرمز 0، أو 1، أو 2...إلى 9).
رقم = خانة رقم
أو خانة
خانة = من "0" إلى "9"
الرقم هو خانات لا يفصل بينها شيء. لهذا لم نقل مثلاً رقم = خانة + رقم بل قلنا مباشرةً رقم = خانة رقم....
ولكن ما فائدة كل هذا؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟
فائدة كل هذا أن لغة كلمات بها محرك إعراب جاهز. لو قدمت له قواعد في صورة PEG سوف يقدم لك إمكانية إعراب أي نص يتماشى مع هذه القواعد. مثلما نعرّف في كلمات دالة أو إجراء أو فصيلة، يمكننا أيضاً أن نعرّف قواعداً. انظر للكود الآتية:
قواعد تعبير : تعبير = حد "+" تعبير أو حد "-" تعبير أو حد حد = أس "×" حد أو أس "÷" حد أو أس أس = أولي "^" أس أو أولي أولي = رقم أو "س" أو "(" تعبير ")" رقم = خانة رقم أو خانة خانة = من "0" إلى "9" نهاية
اطبع تعبير ("1+2+3")
في السطر الأخير نجرب القواعد الجديدة. سوف يطبع مفسر كلمات لك القيمة......لاشيء :(
لماذا؟ في الواقع سوف تقوم كلمات بإعراب التعبير، لكننا لم نطلب منها أن تعطينا شجرة إعراب، لذلك سوف تعود لنا بالقيمة لاشيء. هيا نغير ذلك الموقف! فلنبدأ بشيء بسيط كالأرقام:
رقم = خانة:أ رقم:ب => أ + ب أو خانة خانة = من "0" إلى "9"
لاحظ شيئين:
في السطر الأول قلنا خانة:أ رقم:ب ، هذه طريقتنا في إعطاء أسماء للمكونات التي نعربها.
أننا قلنا في أخر السطر => أ + ب ، وهذه طريقتنا في أن نعود بقيم أثناء الإعراب
يمكن أن نقرأ السطر كله كالآتي: الرقم مكون من خانة هي أ، ورقم أصغر هو ب، وحين نجدهما نعود بالقيمة أ + ب.
لاحظ أن أ و ب هما نصان، فلو أعربنا الرقم "123" فسيكون أ = "1" و ب يساوي "23" (الأرقام تقرأ من اليسار) وبهذا يكون الرقم كله هو أ + ب = "123"
ماذا عن السطر الثاني الذي يقول أو خانة؟ نحن لم نخبره بأي قيمة يعود، لكن لو رأى مفسر كلمات قاعدة ما هي الا استدعاء قاعدة أخرى (نحن لم نفعل سوى استدعاء "خانة") فسيعود بنفس القيمة الآتية من القاعدة المستدعاه. كأني بالضبط قلت أو خانة:أ => أ
ماذا عن السطر خانة = من "0" إلى "9"؟ حين تكون القاعدة ما هي إلا قيمة نصية فالقيمة العائدة منها هي نفس القيمة النصية.
إذاً قد عرفنا ماذا يرجع من رقم. ماذا عن شيء مثل تعبير؟
تعبير = حد:أ "+" تعبير:ب => ["+"، أ، ب] أو حد:أ "-" تعبير:ب => ["-"، أ، ب] أو حد:أ => أ
باللغة البشرية:
التعبير هو حد اسمه أ، ثم علامة "+"، ثم تعبير أصغر اسمه ب ، وفي تلك الحالة ارجع بالمصفوفة ["+"، أ، ب]
أو هو حد اسمه أ، ثم علامة "-"، ثم تعبير أصغر اسمه ب، وهنا ارجع بالمصفوفة ["-"، أ، ب]
أو هو مجرد حد اسمه أ، وفي تلك الحالة ارجع بذلك الحد.
سهل، أليس كذلك؟ بنفس الطريقة نعدل "حد" و "أس" و"أولي" ليكون لدينا القواعد كلها:
قواعد تعبير : تعبير = حد : أ "+" تعبير : ب => ["+"، أ، ب] أو حد : أ "-" تعبير : ب => ["-"، أ، ب] أو حد : أ => أ حد = أس:أ "×" حد:ب => ["×"، أ، ب] أو أس:أ "÷" حد:ب => ["÷"، أ، ب] أو أس:أ => أ أس = عامل:أ "^" أس:ب => ["^"، أ، ب] أو عامل عامل = رقم:أ => كعدد (أ) أو "س" أو "(" تعبير : أ ")" => أ رقم = خانة : أ رقم : ب => أ + ب أو خانة خانة = من "0" إلى "9" نهاية
لاحظ أننا في هذا الجزء التالي قد حولنا الرقم من قيمة نصية إلى قيمة عددية:
عامل = رقم:أ => كعدد (أ)
قد يبدو الأمر صعباً، لكنه أسهل بكثير من كتابة برنامج يأخذ أي صيغة رياضية ويفهمها بطريقة يدوية. القواعد كلها أخذت 30 سطراً لكنها وفرت عشرات أو مئات السطور المطلوبة لعمل مثل هذا البرنامج في لغات أخرى.
سوف تصنع لنا كلمات دالة اسمها "تعبير" (لأننا قد سمينا القواعد "تعبير")، وهذه الدالة إن أعطيناها نصاً فستعطينا شجرة إعراب. جرب أن تضيف هذا السطر في آخر البرنامج:
اطبع تعبير("12+13×14")
سوف يظهر المخرج التالي:
["+"، 12، ["×"، 13، 14]]
في الواقع الكود السابقة ليست دقيقة لأن العمليات الرياضية + - ÷ × بها خاصية left associativity. أي أن تعبير مثل 1-2-5 المفروض أن يكون (1-2)-5، لكن برنامجنا يعتبره 1-(2-5)، أي أنه يعود بالشجرة ["-"، 1، ["-"، 2، 5] بدلاً من الشجرة الصحيحة وهي ["-"، ["-"، 1، 2]، 5]
سبب المشكلة هو أنه كان المفروض في القواعد أن نقول:
تعبير = تعبير + حد
ولكننا قلنا
تعبير = حد + تعبير
للأسف لا يمكن استخدام الطريقة الصحيحة في هذا الإصدار من كلمات بسبب مشكلة اسمها left recursion (هناك طرق لحل تلك المشكلة لكنها لم تطبق في كلمات بعد). لذلك علينا الحذر: البرنامج سيعطي نتائجاً خاطئة في المدخلات أ-ب-ج أو أ÷ب÷ج، ولكن يمكننا استخدام الأقواس في تلك الحالات.
على العموم قد أنهينا جزء إعراب الصيغ الرياضية، ومازال لدينا 70 سطراً أيضاً!
الخميس، 6 ديسمبر 2012
تحقق الإمكان الإنساني
تعلمنا في الفيزياء أن التداخل قد يكون بناءاً أو هداماً [constructive or destructive interference]. قد يدعم بعض الموجات بعضاً وتكون بناءة، أو يصد بعضها بعضاً وتكون هدامة. وقد عشت في هذا العالم كثيراً لأرى التداخلات الهدامة. ولقد مللت.
كم من عبقري كان ليرفع مستوى العلم في البلد، بل في العالم، فقط لو وجد التعليم الكافي، أو الرعاية الصحية، أو من يدعمه، أو من يشجعه؟ لكن البلد قد حكمها اللصوص والسفاحين والطماعين.
كيف كان ليصبح شكل المجتمع لو توقف الناس عن التناحر والسرقة والاستبداد، وبدأ كل شخص يتفرغ ليجيب على سؤال: ما هو الحد الأقصى للإمكان الإنساني؟ ما أفضل شيء نستطيع أن نبنيه، وأفضل علم نستطيع أن نبحثه، وأفضل فكر نستطيع أن ننتجه؟ ما هو الإمكان الحقيقي لنا؟
كيف نحقق العدل والرخاء؟ كيف نواجه الأمراض والتلوث والتصحر؟ ماذا نفعل بشأن المخلوقات التي كادت تنقرض؟
كيف نحل المشاكل الاجتماعية؟ ماذا نفعل تجاه ارتفاع نسب الطلاق، وتمرد الأبناء على آبائهم؟ هل هناك أطفال يُضايقون أو يعتدى عليهم في المدارس؟ كيف نحل تلك المشاكل؟
هل المدن جميلة (وليس فقط نظيفة)؟ هل الناس سعداء بالمشي فيها؟ ما الذي يسبب التعاسة للناس؟ هل يحبون وظائفهم أم يعملون فيها على مضض؟
ولكن قبل أن يحدث ذلك علينا أن نفكر في أسئلة اخرى:
- كيف تتصرف مع الحاكم المستبد؟
- كيف تتصرف مع الصراعات السياسية التي نتجت بعد خلع الحاكم المستبد؟
- كيف تتصرف مع الخونة الذين يريدون العودة للسلطة بأي شكل؟
- كيف تتصرف مع كل عنيد لا يصغى للعقل، وتقدم له الحجه تلو الحجة فلا يناقشك في صحة حجتك أو خطئها، بل يستكبر ويعتبر أن المشكلة الحقيقية أنك لم تفهم قصده، ويبدأ في "شرح" كلامه لك مرة أخرى؟
وإني لم أر مثل ذلك أشياء كبيرة تعتمد على أشياء صغيرة. قبل أن نبدأ في التفكير في التقدم العلمي أو العدالة الاجتماعية عليك أولاً أن تقنع فلاناً أن ينزل من بيته وينتخب، أو أن يراجع قرار كذا، أو ألا يتحيز لكذا. ملايين المعارك الصغيرة كل يوم بين كل أفراد الوطن، وتشعر بالخسارة مع كل حوار يطول وينتهي بعناد، وبعض الناس يأتيه إغراء أن يستبد برأيه هو الآخر، وأن يحكم على الناس أنهم أغبياء ويحتاجون من يجبرهم لا من يحاورهم؛ بعضهم يستسلم للإغراء وآخر يمسك نفسه ويقول لا؛ لن أحل الاستبداد باستبداد.
لا بأس؛ هذا جزء من الرحلة. هذا جزء من البناء، هذا جزء من "تحقق الإمكان الإنساني". الأشياء الكبيرة تعتمد على الأشياء الصغيرة، حقيقة علمية.
ذات مرة نشر عالم اسمه زويكي بحثاً عما سماه "النجمة النيوترونية" Neutron star. كان يقدم تنبؤا عن وجود هذا النوع من النجوم، وكان تنبؤه استناج من خصائص الذرات والنيوترونات. لا تستطيع أن تفصل بين سلوك النجوم/الثقوب السوداء...الخ وبين سلوك الذرات والجزيئات.
وماذا عن الـDNA؟ تركيب لا يرى إلا بالميكروسكوب، ويؤثر على خصائص الكائن الحي وشكله ولونه وطوله وقصره وقوته وضعفه.
الذي يحدث هذه الأيام، من الحوارات والمظاهرات والاتفاقات والمقالات والتصريحات، هو أن الـDNA الخاص بالمجتمع يتشكل. وإني أشتاق لأن أرى المجتمع الوليد وخصائصه.
Labels:
arabic-posts,
nahda,
philosophy,
society
الاثنين، 3 ديسمبر 2012
البوست عبارة عن كود
هذا مثال ورقة بارنسلي، من فرع من الرياضيات يسمى chaos theory، من المدهش حقاً الشكل المعقد الذي يمكن أن يظهر من هذه الكود البسيطة.
لتنفذ هذا البرنامج:
لتنفذ هذا البرنامج:
- حمل لغة كلمات من http://www.kalimat-lang.com
- قم بنسخ ولصق الكود بالكامل في محرر كلمات
- قم بتنفيذ البرنامج
س مشترك ص مشترك س = 0 ص = 0 علامة البداية ارسم.نقطة (س × 30 + 50، ص × 30 + 50)، 5 الاختيار = عشوائي (100) إذا الاختيار = 0 : تحويل1 () وإلا إذا الاختيار < 86 : تحويل2 () وإلا إذا الاختيار < 93 : تحويل3 () وإلا : تحويل4 () تم اذهب إلى البداية إجراء تحويل1 (): س = 0 ص = 0.16 × ص نهاية إجراء تحويل2 (): س = 0.85 × س + 0.04 × ص ص = - 0.04 × س + 0.85 × ص + 1.6 نهاية إجراء تحويل3 (): س = 0.2 × س - 0.26 × ص ص = 0.23 × س + 0.22 × ص + 1.6 نهاية إجراء تحويل4 (): س = - 0.15 × س + 0.28 × ص ص = 0.26 × س + 0.24 × ص + 0.44 نهاية
Labels:
arabic-posts,
fun,
kalimat,
math,
programming
السبت، 1 ديسمبر 2012
الرد على ما يسمى نقداً لكلمات
قام أحد المبرمجين العرب بإنشاء لغة برمجة جديدة تسمى إبداع. إنشاء لغات برمجة عربية جديدة هو أمر مرحب به، وقد قلت ذلك كثيراً على مدونتي. مصمم اللغة يفترض أن لغته هي أفضل لغة عربية حالياً، ولكي يفعل ذلك قام بمقارنتها بباقي اللغات العربية الموجودة، ومنها بالطبع كلمات، وبالطبع كانت كلمات خاسرة في مقارنته :)
يقول المؤلف:
(وهو كما ترى كرم من المؤلف؛ إن كلمات بالنسبة له هي أفضل ما في "فترة ما قبل ظهور إبداع" التي يتحدث كأنها بداية عصرٍ جديد من البرمجة)
من حق أي إنسان أن ينتقد كلمات (أنا شخصياً أنتقدها كثيراً) لكن المشكلة أنه قد قدم نقداً عشوائياً غريباً، وقد قرأت نقده هذا سابقاً ولم أردّ، لكن الوضع صار يمكن أن يؤثر على كلمات: إن هذا المبرمج سوف يقوم بتسويق لغته في كل مكان، ومع كل مرة يروج فيها لها سوف يأتي ذكر المقارنة بكلمات (وهو يقدم لها نقداً مطولاً في التوثيق الرسمي للغة)، وإني أخشى أن يصدقه الناس في كلامه ويعرضون عن تجربة لغة كلمات بسبب الانتقادات الغريبة التي يوجهها.
وأخشى أن يظن الناس أن لغته هي ما يمثل حالة لغات البرمجة العربية حالياً (وبالتالي يظنون أنه حال سيء)، مما يؤثر على انتشار فكرة لغات البرمجة العربية عموماً.
ما علينا، هيا نرد على انتقاداته. أريد أولاً أن أنبه لشيء، هو أن كلمات ليست اللغة الوحيدة التي تم انتقادها بهذا الشكل من قبل مصمم "إبداع"، بل إنه قد قدم نفس المعاملة للغات مثل سي شارب أو بايثون أو جافا أو...أو...، وفي الواقع حظ كلمات كان أفضل من كل هؤلاء. أنظر مثلاً كيف يتكلم عن خاصية interfaces الموجودة في لغات مثل جافا أو سي شارب:
وهكذا نجده يتحدث عن إمكانيات مثل struct, union, pointer, delegate في لغات ++C ,و #C وجافا وكلها في نظره خدعة أو فقاعة أو تفاهة أو مناورة تسويقية، ويبدو أن الكاتب يخلط بين عدم معرفته لأسباب وجود الإمكانية وبين عدم ضرورة وجودها أصلاً.
مرة أخرى: ما علينا. هيا نرى نقده للغة كلمات إذاً...
يقول الكاتب:
هي من اللغات ذات التنويع المتغير ،dynamically typed و هذا النوع لا يصلح لكتابة البرامج التي تحتا ج إلي سرعات فائقة في التنفيذ، و كذلك ُيساعد في الوقوع فللي أخطاء التكويد المنطقية لأن اللغة لا تقيد المتغير بنوع بيانات معيَن.
بدايةً الكاتب يمزج بين العيوب والأذواق - هناك لغات كثيرة جداً ناجحة وفي نفس الوقت dynamically typed مثل لغة Python أو JavaScript. هذا ليس "عيباً" في كلمات إلا بقدر ما هو عيب في بايثون: أنها لا تلائم احتياجات معينة أو أنواع معينة من التطبيقات وليس عيباً مطلقاً.
عموماً أنا أنوي على المدى الطويل تقديم static type checking في لغة كلمات. لماذا لم أصنعه حالياً؟ لأن الـtype systems صعبة!
إضافة الـgenerics ليست أمراً سهلاً، وكذلك الـtype variance. وهناك أخطاء في هذه الأمور وقع فيها مصممو لغة الجافا نفسها ولابد من التعامل مع هذه الأشياء بحذر.
(طبعاً هي أمور لا تؤرق كاتب لغة إبداع لأنه قدم type system بسيطة جداً في لغته).
ثم يقول:
اللغة تحتوي علي مكونين في غاية التشابه هما: الإجراء، الدالة. و كان يجب ألا تضم اللغة مكونين متشابهين كهذين علي الإطلاق؛ حيث أن هذا لا داعي له منطقياً، بل و يسبب تشابهُّما الشديد إلي البلبلة عند المبتدئين.
يا لثقته! أنظر كيف يستخدم كلمات قوية مثل "على الإطلاق"، "لا داعي منطقياً"، بينما هو مرة أخرى لا يقدم سوى رأياً شخصياً. هل جاء بمبتدئين وعلمهم البرمجة بكلمات، ثم رأى البلبلة؟ هل أجرى هذه التجارب بمعايير علمية؟ لقد جعلتُ الإجراءات بهذه الطريقة كمحاولة مني لتسهيل تعلم اللغة بإعطاء أسماء مختلفة لمفاهيم مختلفة؛ لكني لم أدّع "هكذا" أن هذا هو المنطقي، بل قلت أنها تجربة وأن تدريب الأطفال وملاحظتهم هو الذي سيخبرنا بالنتيجة.
ثم يقول:
اللغة تحتوي علي مكوني: المصفوفات arrays، القواميس dicts. و كان بالإمكان ضم هذين المكونين في مكونٍ واحد، و هذا سيسهل علي المبتدئين كثيراً لأنه يضم المكونات المتشابهة التكوين و الوظيفة في مكونٍ واحدٍ أشمل
هل من عيوب اللغة أنها لم تفعل ما "كان بالإمكان"؟ هناك أشياء كثيرة ممكنة، ومصمم اللغة يختار ما ينفذه منها. عموماً معظم اللغات تفصل بين الإمكانيتين ماعدا بعض اللغات مثل Lua توحّد بينهما كما يريد. ولو نظرت للأمر من ناحية algorithmic complexity أو من ناحية الـperformance بشكل عام لوجدت مميزات للفصل بينهما.
ثم يقول (قمت بتجميع بعض العيوب لتسريع الأمر):
الدوال و الإجراءات في كلمات ضعيفة البنية؛ فهي تعيد خرجاً واحداً فقط، ولا يمكن إعطاء قيمٍ ابتدائيةٍ لمدخلات الدالة أو الإجراء.
..الفصائل في كلمات ثرثارة؛ فلكي تُعَّرِّف محتويات فصيلةٍ ما فيجب عليك كتابة كلامٍ كثير.
كلمات مصنوعة لتعليم الأطفال البرمجة، لذلك قمت بتبسيط الsemantics والsyntax، وتكرار بعض التركيبات لتذكير المبرمج بفائدتها. مرة أخرى مسألة آراء شخصية، ومسألة ملاءمة الأداة للهدف.
تحتوي كلمات علي أوامر "علامة" و "اذهب إلى"، و اللذين يكافئان "Goto"
وما المشكلة؟ لو تحدثت عن الناحية التعليمية فمصمم لغة SmallBasic من مايكروسوفت يدافع عن goto (المصدر هنا)، ومن الناحية الاحترافية فهذا الأمر مستخدم أحياناً في Linux Kernel.
تعبير الحلقات التكرارية ضعيفٌ للغاية، حيث لا يتيح تغيير مقدار الخطوة في العملية إلا بقيمة زيادةٍ مقدارها 1 (و قد نبه م. محمد سامي إلي أنه ينوي تدارك هذه الجزئية في الإصدارات القادمة بإذن الله عز و جل)
أتمنى أن يحدث الكاتب معلوماته، لأن هذه الإمكانية قد تم تداركها بالفعل منذ أشهر.
المكتبة حتي الآن مبنيةٌ داخل المفسر نفسه، و ليست قائمةً بذاتها و ليست مكتوبةً بلغة كلمات نفسها بل بلغة الـ++C مع مكتبة الـQT. لا يوجد مترجمٌ قويٌ للغة حتي الآن، و كل ما يوجد هو مفسرٌ يتيح لنا استخدام بعض مكونات مكتبة الـQT،
ما المشكلة في كون اللغة مفسرة لا مترجمة؟ هناك لغات من أنجح اللغات في العالم ومفسرة. أما فكرة أنه لا يمكن سوى استخدام مكونات Qt فهو أيضاً غير صحيح (ربما تكون معلومات الكاتب قديمة). كلمات يوجد بها إمكانية FFI التي تتيح استدعاء إجراءات مكتوبة بالسي من مكتبات DLL. وهنا نراها تنادي دوالاً من مكتبات لينكس ومن مكتبات Win32 API.
الشيء الوحيد الذي ينقص هو إمكانية تنفيذ برامج كلمات بدون الحاجة إلى بيئة تطوير كلمات، وهو أيضاً شيء قد أضفته لكنه لا يعمل حالياً بسبب بعض الأخطاء، وأتمنى أن يأتي الدور لإكماله. [تحديث: ثم إعادة تشغيل خاصية عمل الملفات التنفيذية في كلمات منذ إصدارة يناير 2013]
لا يمكن كتابة أوامرٍ بلغة التجميع assembly في برنامج كلمات
إني أتعجب من بعض الأشياء التي يراها صاحب النقد عيوباً. بحسب علمي لا توجد لغات بها هذه الإمكانية إلا لغات قليلة جداً مثل Delphi, C ولغة التجميع نفسها. ولكن انتظر! إن صاحب المقال يذكر سبب افتراضه أن هذا عيباً:
...و هذا يجعلها غير قادرةٍ علي: إنتاج مكتبتها باستخدامها هي نفسها.
كلام خطأ؛ راجع إمكانية FFI
....إنتاج برامجٍ تعمل علي المتحكمات الميكروئية microcontrollers
في تلك الحالة استخدم سي أو لغة التجميع
...كتابة البرمجيات الأخري التي نحتاج فيها إلي التعامل مع الذاكرة مباشرةً، مثل، أنظمة التشغيل، المترجمات compilers، المفسرات interpreters.
عجيب أن يأتي هذا من مبرمج يرفض فكرة الـpointers. عموماً يمكن كتابة مترجمات، مفسرات، بلغات خالية من إمكانية لغة التجميع، مثلاً مترجم لغة سي شارب هو نفسه مكتوب بالسي شارب، ومترجم الجافا مكتوب بالجافا، وهناك مترجمات ومفسرات كثيرة مكتوبة بالبايثون.
أيضاً هناك نظم تشغيل مكتوبة بالجافا والسي شارب. كيف تصرف كاتبوها؟ غالباً ينظرون إلى ما يحتاج للكتابة بلغة التجميع ويضعونه في مكتبة خارجة ثم يقومون باستدعائه من البرنامج الأصلي.
اللغة لم تستقر في تصميمها بعد، و لم توضع لها خطةٌ توضح حجمها النهائي المتوقع حتي الآن، ونحن نري بالفعل أن اللغة يزيد حجمها يوماً بعد يوم.
هناك نوع من "خارطة الطريق" قد كتبته لكلمات (وهو هنا لمن يريد الاطلاع عليه)، لكني أشعر أن الكاتب لديه حساسية من موضوع ازدياد حجم اللغات. حتى أنه يعيب على لغة سي شارب أن حجمها يزداد في كل إصدارة.
هناك بالفعل من يريد أن يحافظ على لغته صغيرة وminimalist وأنا أتفهم مزايا هذا الموضوع (مثلا لغة Google Go تفعل هذا)، لكن يبدو أن الكاتب يرى النمو والتطور عيباً شاملاً في أي لغة.
اللغات مثل سي شارب تتطور لأن عالم البرمجة يتغير: سي شارب صار فيها إمكانيات functional programming حين بدأ نجم البرمجة المتوازية يعلو، وإمكانية Linq ظهرت لتسهيل التعامل مع البيانات المتنوعة في البرامج الكبيرة (ولأسباب أخرى)، وإمكانية generators ظهرت لتبسط أشياءً كانت من قبل معقدة، وإمكانية async/await ظهرت مرة أخرى من أجل البرمجة المتوازية.
سي شارب لغة معقدة لأنها مصنوعة لحل مشاكل معقدة.هل كان يمكن أن تكون أبسط؟ ربما. لكن لا نستطيع أن نقول أن تطورها المستمر هو عيب خطير فيها لابد أن يتوقف.
الوحدات في كلمات تتيح لنا إنشاء إجراءاتٍ و دوالٍ حرة (أي لا يلزم أن تكون مكتوبةً في فصيلةٍ ما)، و هو ما يجعلنا نعاني من مساوئ نموذج البرمجة الإجرائية في المشاريع الكبيرة، و هذه الصفة تناقض مبدأ الأمن الذي نريده في لغة البرمجة القوية.
يبدو أن الكاتب قد غير رأيه في هذا الموضوع لأن هذه الإمكانية (بحسب ما فهمت) موجوده في لغته أيضاً، لكنه لم يحذف هذا الجزء من نقد كلمات وأرجو أن يحدّث ما كتب.
الوصول إلي مكونات الفصيلة غير مُوَحَّد الشكل، فنحن نصل إلي المتغير الداخلي للكائن عن طريق كتابة اسمه ثم كتابة اسم الكائن بعده، أما الإجراءات و الدوال فيجب أن يكتب اسم الكائن أولاً، ثم نتبعه بعلامة : ثم اسم الإجراء أو الدالة.
الكاتب يتحدث عن إمكانية أن أقول
س = سيارة جديد
لون سقف س = "أزرق"
ويريد بدلاً من ذلك أن تكون:
س_سقف_لون = "أزرق"
...وذلك لكي يكون هناك توافق بين field access و method call.
أنا اخترت أن تكون الكود طبيعية أكثر وأشبه باللغة العادية.
ليس فيها تعبيرٌ لمعالجة الاستثناءات exception handling.
هذه الإمكانية مؤجلة حتى أجد طريقة لصنعها بشكل أفضل (وليس مجرد محاكاه لما يحدث في لغات موجودة)، لأني أرى شكلها الحالي معقداً.
لا تحتوي علي مكونٍ هامٍ للغاية هو التعدادات enumerations
ماشي. ولا لغات كثيرة أخرى.
لا تحتوي علي فكرة ال ) delegatingالموجود في لغات مثل الل#.(C
ممم...كلمات حالياً (في أحدث إصداراتها) بها فكرة first class functions وهي مشابهة في الأهداف لما صنعت من أجله فكرة delegates. ربما يمكن الآن في كلمات إضافة الـdelegates في مكتبة.
نلاحظ أن الكاتب قد رفض فكرة الـdelegates كما هي في سي شارب ولم يضفها إلى لغته، لكنه قال أن لديه إمكانية أخرى في لغته هي ما يسميه "الإجراء الحر" تعوض النقص.
لست متأكداً أنني قد فهمت مقصده، لكن الإجراءات الحرة لا تقوم بدور الdelegates!
الكاتب يركز على جزء أن الـdelegate تسمح باستدعاء أكثر من إجراء مرة واحدة؛ لكن ليس هذا الاستخدام الأساسي لها: الاستخدام الأساسي هو فكرة تخزين إجراء في متغير أو تمريره لإجراء آخر. هل يمكن صنع هذا في لغة إبداع؟ لا أعتقد.
كما قلت، توجد في لغة إبداع بعض الأفكار الجيدة، وربما تتطور مع الوقت وتصير لغة قوية، لأ أريد أن يكون مقالي هذا دافعاً للكاتب (أو لأي مبرمج عربي آخر) أن يترك المحاولة لعمل لغات برمجة عربية.
لكني لا أحب أسلوبه في تحطيم اللغات الأخرى بدون خلفية علمية وايضاً بدون معرفة لأسباب القرارات المتخذة في كل لغة. ولا أحب الثقة الغريبة في أسلوبه حيث كل كلامه "منطقي" أو "بالتأكيد" بينما الأمر لا يخرج عن الآراء الشخصية.
وقد ابتعدت شخصياً عن الهجوم على أية لغة برمجة عربية أخرى مفضلاً أن أجعل كلمات تتحدث عن نفسها، ولكن هذا المقال هو حالة خاصة. هذا نقد غير منصف للغة كلمات يوزع رسمياً مع لغة برمجة عربية أخرى!
وعموما اشعر بالضيق من كتابة هذا المقال..ومازلت أفكر هل أبقي عليه أم أخفيه من المدونة..
يقول المؤلف:
بداية: ُتعد لغة كلمات أرقي لغات البرمجة العربية في فترة ما قبل ظهور إبداع علي الطلق، فلها الميزات التالية...
(وهو كما ترى كرم من المؤلف؛ إن كلمات بالنسبة له هي أفضل ما في "فترة ما قبل ظهور إبداع" التي يتحدث كأنها بداية عصرٍ جديد من البرمجة)
من حق أي إنسان أن ينتقد كلمات (أنا شخصياً أنتقدها كثيراً) لكن المشكلة أنه قد قدم نقداً عشوائياً غريباً، وقد قرأت نقده هذا سابقاً ولم أردّ، لكن الوضع صار يمكن أن يؤثر على كلمات: إن هذا المبرمج سوف يقوم بتسويق لغته في كل مكان، ومع كل مرة يروج فيها لها سوف يأتي ذكر المقارنة بكلمات (وهو يقدم لها نقداً مطولاً في التوثيق الرسمي للغة)، وإني أخشى أن يصدقه الناس في كلامه ويعرضون عن تجربة لغة كلمات بسبب الانتقادات الغريبة التي يوجهها.
وأخشى أن يظن الناس أن لغته هي ما يمثل حالة لغات البرمجة العربية حالياً (وبالتالي يظنون أنه حال سيء)، مما يؤثر على انتشار فكرة لغات البرمجة العربية عموماً.
ما علينا، هيا نرد على انتقاداته. أريد أولاً أن أنبه لشيء، هو أن كلمات ليست اللغة الوحيدة التي تم انتقادها بهذا الشكل من قبل مصمم "إبداع"، بل إنه قد قدم نفس المعاملة للغات مثل سي شارب أو بايثون أو جافا أو...أو...، وفي الواقع حظ كلمات كان أفضل من كل هؤلاء. أنظر مثلاً كيف يتكلم عن خاصية interfaces الموجودة في لغات مثل جافا أو سي شارب:
...إذاً يتَضح لنا أن هذه الميزة ما هى إلا فقاعة فارغة ُتقال و لا حقيقة لها، و السبب الوحيد لقولها هو دعم السبب الحقيقى لاستخدام الواجهات، و جعل الأسباب كثيرة تملأ ناظرى القارئ لتقِنعه بيسر بأهميتها، فى حين أنه ليس هناك سبب حقيقى َيستحق النظر إلا واحداً أو اثنين على الأكثر...
وهكذا نجده يتحدث عن إمكانيات مثل struct, union, pointer, delegate في لغات ++C ,و #C وجافا وكلها في نظره خدعة أو فقاعة أو تفاهة أو مناورة تسويقية، ويبدو أن الكاتب يخلط بين عدم معرفته لأسباب وجود الإمكانية وبين عدم ضرورة وجودها أصلاً.
مرة أخرى: ما علينا. هيا نرى نقده للغة كلمات إذاً...
يقول الكاتب:
هي من اللغات ذات التنويع المتغير ،dynamically typed و هذا النوع لا يصلح لكتابة البرامج التي تحتا ج إلي سرعات فائقة في التنفيذ، و كذلك ُيساعد في الوقوع فللي أخطاء التكويد المنطقية لأن اللغة لا تقيد المتغير بنوع بيانات معيَن.
بدايةً الكاتب يمزج بين العيوب والأذواق - هناك لغات كثيرة جداً ناجحة وفي نفس الوقت dynamically typed مثل لغة Python أو JavaScript. هذا ليس "عيباً" في كلمات إلا بقدر ما هو عيب في بايثون: أنها لا تلائم احتياجات معينة أو أنواع معينة من التطبيقات وليس عيباً مطلقاً.
عموماً أنا أنوي على المدى الطويل تقديم static type checking في لغة كلمات. لماذا لم أصنعه حالياً؟ لأن الـtype systems صعبة!
إضافة الـgenerics ليست أمراً سهلاً، وكذلك الـtype variance. وهناك أخطاء في هذه الأمور وقع فيها مصممو لغة الجافا نفسها ولابد من التعامل مع هذه الأشياء بحذر.
(طبعاً هي أمور لا تؤرق كاتب لغة إبداع لأنه قدم type system بسيطة جداً في لغته).
ثم يقول:
اللغة تحتوي علي مكونين في غاية التشابه هما: الإجراء، الدالة. و كان يجب ألا تضم اللغة مكونين متشابهين كهذين علي الإطلاق؛ حيث أن هذا لا داعي له منطقياً، بل و يسبب تشابهُّما الشديد إلي البلبلة عند المبتدئين.
يا لثقته! أنظر كيف يستخدم كلمات قوية مثل "على الإطلاق"، "لا داعي منطقياً"، بينما هو مرة أخرى لا يقدم سوى رأياً شخصياً. هل جاء بمبتدئين وعلمهم البرمجة بكلمات، ثم رأى البلبلة؟ هل أجرى هذه التجارب بمعايير علمية؟ لقد جعلتُ الإجراءات بهذه الطريقة كمحاولة مني لتسهيل تعلم اللغة بإعطاء أسماء مختلفة لمفاهيم مختلفة؛ لكني لم أدّع "هكذا" أن هذا هو المنطقي، بل قلت أنها تجربة وأن تدريب الأطفال وملاحظتهم هو الذي سيخبرنا بالنتيجة.
ثم يقول:
اللغة تحتوي علي مكوني: المصفوفات arrays، القواميس dicts. و كان بالإمكان ضم هذين المكونين في مكونٍ واحد، و هذا سيسهل علي المبتدئين كثيراً لأنه يضم المكونات المتشابهة التكوين و الوظيفة في مكونٍ واحدٍ أشمل
هل من عيوب اللغة أنها لم تفعل ما "كان بالإمكان"؟ هناك أشياء كثيرة ممكنة، ومصمم اللغة يختار ما ينفذه منها. عموماً معظم اللغات تفصل بين الإمكانيتين ماعدا بعض اللغات مثل Lua توحّد بينهما كما يريد. ولو نظرت للأمر من ناحية algorithmic complexity أو من ناحية الـperformance بشكل عام لوجدت مميزات للفصل بينهما.
ثم يقول (قمت بتجميع بعض العيوب لتسريع الأمر):
الدوال و الإجراءات في كلمات ضعيفة البنية؛ فهي تعيد خرجاً واحداً فقط، ولا يمكن إعطاء قيمٍ ابتدائيةٍ لمدخلات الدالة أو الإجراء.
..الفصائل في كلمات ثرثارة؛ فلكي تُعَّرِّف محتويات فصيلةٍ ما فيجب عليك كتابة كلامٍ كثير.
كلمات مصنوعة لتعليم الأطفال البرمجة، لذلك قمت بتبسيط الsemantics والsyntax، وتكرار بعض التركيبات لتذكير المبرمج بفائدتها. مرة أخرى مسألة آراء شخصية، ومسألة ملاءمة الأداة للهدف.
تحتوي كلمات علي أوامر "علامة" و "اذهب إلى"، و اللذين يكافئان "Goto"
وما المشكلة؟ لو تحدثت عن الناحية التعليمية فمصمم لغة SmallBasic من مايكروسوفت يدافع عن goto (المصدر هنا)، ومن الناحية الاحترافية فهذا الأمر مستخدم أحياناً في Linux Kernel.
تعبير الحلقات التكرارية ضعيفٌ للغاية، حيث لا يتيح تغيير مقدار الخطوة في العملية إلا بقيمة زيادةٍ مقدارها 1 (و قد نبه م. محمد سامي إلي أنه ينوي تدارك هذه الجزئية في الإصدارات القادمة بإذن الله عز و جل)
أتمنى أن يحدث الكاتب معلوماته، لأن هذه الإمكانية قد تم تداركها بالفعل منذ أشهر.
المكتبة حتي الآن مبنيةٌ داخل المفسر نفسه، و ليست قائمةً بذاتها و ليست مكتوبةً بلغة كلمات نفسها بل بلغة الـ++C مع مكتبة الـQT. لا يوجد مترجمٌ قويٌ للغة حتي الآن، و كل ما يوجد هو مفسرٌ يتيح لنا استخدام بعض مكونات مكتبة الـQT،
ما المشكلة في كون اللغة مفسرة لا مترجمة؟ هناك لغات من أنجح اللغات في العالم ومفسرة. أما فكرة أنه لا يمكن سوى استخدام مكونات Qt فهو أيضاً غير صحيح (ربما تكون معلومات الكاتب قديمة). كلمات يوجد بها إمكانية FFI التي تتيح استدعاء إجراءات مكتوبة بالسي من مكتبات DLL. وهنا نراها تنادي دوالاً من مكتبات لينكس ومن مكتبات Win32 API.
الشيء الوحيد الذي ينقص هو إمكانية تنفيذ برامج كلمات بدون الحاجة إلى بيئة تطوير كلمات، وهو أيضاً شيء قد أضفته لكنه لا يعمل حالياً بسبب بعض الأخطاء، وأتمنى أن يأتي الدور لإكماله. [تحديث: ثم إعادة تشغيل خاصية عمل الملفات التنفيذية في كلمات منذ إصدارة يناير 2013]
لا يمكن كتابة أوامرٍ بلغة التجميع assembly في برنامج كلمات
إني أتعجب من بعض الأشياء التي يراها صاحب النقد عيوباً. بحسب علمي لا توجد لغات بها هذه الإمكانية إلا لغات قليلة جداً مثل Delphi, C ولغة التجميع نفسها. ولكن انتظر! إن صاحب المقال يذكر سبب افتراضه أن هذا عيباً:
...و هذا يجعلها غير قادرةٍ علي: إنتاج مكتبتها باستخدامها هي نفسها.
كلام خطأ؛ راجع إمكانية FFI
....إنتاج برامجٍ تعمل علي المتحكمات الميكروئية microcontrollers
في تلك الحالة استخدم سي أو لغة التجميع
...كتابة البرمجيات الأخري التي نحتاج فيها إلي التعامل مع الذاكرة مباشرةً، مثل، أنظمة التشغيل، المترجمات compilers، المفسرات interpreters.
عجيب أن يأتي هذا من مبرمج يرفض فكرة الـpointers. عموماً يمكن كتابة مترجمات، مفسرات، بلغات خالية من إمكانية لغة التجميع، مثلاً مترجم لغة سي شارب هو نفسه مكتوب بالسي شارب، ومترجم الجافا مكتوب بالجافا، وهناك مترجمات ومفسرات كثيرة مكتوبة بالبايثون.
أيضاً هناك نظم تشغيل مكتوبة بالجافا والسي شارب. كيف تصرف كاتبوها؟ غالباً ينظرون إلى ما يحتاج للكتابة بلغة التجميع ويضعونه في مكتبة خارجة ثم يقومون باستدعائه من البرنامج الأصلي.
اللغة لم تستقر في تصميمها بعد، و لم توضع لها خطةٌ توضح حجمها النهائي المتوقع حتي الآن، ونحن نري بالفعل أن اللغة يزيد حجمها يوماً بعد يوم.
هناك نوع من "خارطة الطريق" قد كتبته لكلمات (وهو هنا لمن يريد الاطلاع عليه)، لكني أشعر أن الكاتب لديه حساسية من موضوع ازدياد حجم اللغات. حتى أنه يعيب على لغة سي شارب أن حجمها يزداد في كل إصدارة.
هناك بالفعل من يريد أن يحافظ على لغته صغيرة وminimalist وأنا أتفهم مزايا هذا الموضوع (مثلا لغة Google Go تفعل هذا)، لكن يبدو أن الكاتب يرى النمو والتطور عيباً شاملاً في أي لغة.
اللغات مثل سي شارب تتطور لأن عالم البرمجة يتغير: سي شارب صار فيها إمكانيات functional programming حين بدأ نجم البرمجة المتوازية يعلو، وإمكانية Linq ظهرت لتسهيل التعامل مع البيانات المتنوعة في البرامج الكبيرة (ولأسباب أخرى)، وإمكانية generators ظهرت لتبسط أشياءً كانت من قبل معقدة، وإمكانية async/await ظهرت مرة أخرى من أجل البرمجة المتوازية.
سي شارب لغة معقدة لأنها مصنوعة لحل مشاكل معقدة.هل كان يمكن أن تكون أبسط؟ ربما. لكن لا نستطيع أن نقول أن تطورها المستمر هو عيب خطير فيها لابد أن يتوقف.
الوحدات في كلمات تتيح لنا إنشاء إجراءاتٍ و دوالٍ حرة (أي لا يلزم أن تكون مكتوبةً في فصيلةٍ ما)، و هو ما يجعلنا نعاني من مساوئ نموذج البرمجة الإجرائية في المشاريع الكبيرة، و هذه الصفة تناقض مبدأ الأمن الذي نريده في لغة البرمجة القوية.
يبدو أن الكاتب قد غير رأيه في هذا الموضوع لأن هذه الإمكانية (بحسب ما فهمت) موجوده في لغته أيضاً، لكنه لم يحذف هذا الجزء من نقد كلمات وأرجو أن يحدّث ما كتب.
الوصول إلي مكونات الفصيلة غير مُوَحَّد الشكل، فنحن نصل إلي المتغير الداخلي للكائن عن طريق كتابة اسمه ثم كتابة اسم الكائن بعده، أما الإجراءات و الدوال فيجب أن يكتب اسم الكائن أولاً، ثم نتبعه بعلامة : ثم اسم الإجراء أو الدالة.
الكاتب يتحدث عن إمكانية أن أقول
س = سيارة جديد
لون سقف س = "أزرق"
ويريد بدلاً من ذلك أن تكون:
س_سقف_لون = "أزرق"
...وذلك لكي يكون هناك توافق بين field access و method call.
أنا اخترت أن تكون الكود طبيعية أكثر وأشبه باللغة العادية.
ليس فيها تعبيرٌ لمعالجة الاستثناءات exception handling.
هذه الإمكانية مؤجلة حتى أجد طريقة لصنعها بشكل أفضل (وليس مجرد محاكاه لما يحدث في لغات موجودة)، لأني أرى شكلها الحالي معقداً.
لا تحتوي علي مكونٍ هامٍ للغاية هو التعدادات enumerations
ماشي. ولا لغات كثيرة أخرى.
لا تحتوي علي فكرة ال ) delegatingالموجود في لغات مثل الل#.(C
ممم...كلمات حالياً (في أحدث إصداراتها) بها فكرة first class functions وهي مشابهة في الأهداف لما صنعت من أجله فكرة delegates. ربما يمكن الآن في كلمات إضافة الـdelegates في مكتبة.
نلاحظ أن الكاتب قد رفض فكرة الـdelegates كما هي في سي شارب ولم يضفها إلى لغته، لكنه قال أن لديه إمكانية أخرى في لغته هي ما يسميه "الإجراء الحر" تعوض النقص.
لست متأكداً أنني قد فهمت مقصده، لكن الإجراءات الحرة لا تقوم بدور الdelegates!
الكاتب يركز على جزء أن الـdelegate تسمح باستدعاء أكثر من إجراء مرة واحدة؛ لكن ليس هذا الاستخدام الأساسي لها: الاستخدام الأساسي هو فكرة تخزين إجراء في متغير أو تمريره لإجراء آخر. هل يمكن صنع هذا في لغة إبداع؟ لا أعتقد.
وأخيراً
كما قلت، توجد في لغة إبداع بعض الأفكار الجيدة، وربما تتطور مع الوقت وتصير لغة قوية، لأ أريد أن يكون مقالي هذا دافعاً للكاتب (أو لأي مبرمج عربي آخر) أن يترك المحاولة لعمل لغات برمجة عربية.
لكني لا أحب أسلوبه في تحطيم اللغات الأخرى بدون خلفية علمية وايضاً بدون معرفة لأسباب القرارات المتخذة في كل لغة. ولا أحب الثقة الغريبة في أسلوبه حيث كل كلامه "منطقي" أو "بالتأكيد" بينما الأمر لا يخرج عن الآراء الشخصية.
وقد ابتعدت شخصياً عن الهجوم على أية لغة برمجة عربية أخرى مفضلاً أن أجعل كلمات تتحدث عن نفسها، ولكن هذا المقال هو حالة خاصة. هذا نقد غير منصف للغة كلمات يوزع رسمياً مع لغة برمجة عربية أخرى!
وعموما اشعر بالضيق من كتابة هذا المقال..ومازلت أفكر هل أبقي عليه أم أخفيه من المدونة..
الخميس، 29 نوفمبر 2012
هيا نستخدم تعبيرات لامدا(1): الترتيب والمقارنة
هب أن لدينا هذا الإجراء الذي يرتب مصفوفة من الأعداد (الإجراء بطيء لكنه بسيط بما يكفي للأهداف التعليمية):
إجراء رتب (م): لكل أ من 1 إلى عدد (م): لكل ب من أ + 1 إلى عدد (م): إذا م [أ] > م [ب]: مؤقت = م [أ] م [أ]= م [ب] م [ب]= مؤقت تم تابع تابع نهاية م = [5، 12، 8، 4، 3، 9] رتب (م) اطبع م
هذا الإجراء سيقوم بالمهمة المطلوبة، لكن من الصعب استخدامه في تطبيقات كثيرة: لا يمكن تطبيقه إلا على مصفوفة من الأعداد أو النصوص (لأنه يستخدم المعامل أكبر من)، ولا يمكن استخدامه إلا للترتيب التصاعدي.
الإجراء يأخذ عاملاً parameter هو المصفوفة 'م'، ماذا لو كان يأخذ عاملاً آخر هو الدالة التي يستخدمها في سطر المقارنة؟
إجراء رتب (م، دالة.المقارنة): لكل أ من 1 إلى عدد (م): لكل ب من أ + 1 إلى عدد (م): إذا دالة.المقارنة : تنفيذها (م [أ]، م [ب]): مؤقت = م [أ] م [أ]= م [ب] م [ب]= مؤقت تم تابع تابع نهاية م = [5، 12، 8، 4، 3، 9] رتب (م، λ س، ص : س > ص) اطبع م
لقد قمنا بثلاث تغييرات صغيرة:
- أضفنا عاملاً هو دالة.المقارنة
- بدلاً من الاختبار م[أ] > م[ب]، جعلناه دالة.المقارنة: تنفيذها(م[أ]، م[ب])
- عند استدعاء الإجراء رتب، أعطيناه دالة مقارنة هي λ س، ص : س > ص، أي الدالة التي لو أخذت س و ص تعود بالقيمة س>ص (القيمة 'صحيح' أو 'خطأ' حسب نتيجة المقارنة).
ماذا لو أردنا ترتيب مصفوفة من الأشخاص حسب السن مثلاً؟ (اعتبر لدينا فصيلة اسمها "شخص" بها بيان اسمه "سن"). وقتها يكفي أن نقول هذا:
رتب (الأشخاص، λ أ، ب : سن أ > سن ب)
ماذا لو أردنا ترتيب الأشخاص حسب السن تنازلياً؟ يكفي تغيير العلامة في تعبير لامدا.
Labels:
arabic-posts,
kalimat
السبت، 24 نوفمبر 2012
تعبيرات لامدا في كلمات
تم إطلاق نسخة نوفمبر 2012 من لغة كلمات، وفيها أنواع جديدة من التعبيرات: الإجراء كذا، الدالة كذا. مثلاً لو قلت:
سوف تجد في المتغير س كائناً object يسمح لي باستدعاء الإجراء 'ترحيب' متى أردت. وكذلك ص يحمل وسيلة لاستدعاء الدالة 'مجموع' استدعيهما هكذا:
السطر الأول يطبع الترحيب على الشاشة، والسطر الثاني يضع القيمة 15 في المتغير ب.
لماذا قلنا "س: تنفيذها( ) " في أول سطر بينما قلنا "ب = ص: تنفيذها(...)" في الثاني؟ لأن س تعبر عن إجراء بينما ص تعبر عن دالة.
الآن ما فائدة هذا الاسلوب في إيجاد قيم تعبر عن الإجراءات والدوال؟ هيا نضرب مثلاً ظريفاً:
ماذا فعلنا؟ الدالة كلهم تأخذ مصفوفة ودالة اخرى اختبارية (تعود بالقيمة صحيح أو خطأ)، وتقوم بتطبيق الدالة على كل قيمة في المصفوفة، بحيث لو عادت تلك الدالة بـصحيح لكل القيم، تعود الدالة الأم أيضاً بـصحيح، وإلا عادت بـخطأ.
والآن لم تعد تحتاج كتابة هذا الـ loop مرة أخرى للتأكد أن شرطاً ما ينطبق على كل القيم في مصفوفة!
الأجمل من هذا أن كلمات سوف يكون بها مكتبة جاهزة فيها الدالة كلهم، بالإضافة لدوال أخرى شبيهة هي بعضهم، ليس.كلهم، كلهم.ليسوا ، بحيث يكون اختبار القيم في المصفوفات بسهولة كتابة سطر واحد في كثير من الأحيان.
لحظة...سطر واحد؟ ألم أضطر لكتابة الدالة زوجي في المثال السابق؟ هذا يجعل الموضوع يأخذ أكثر من سطر واحد للأسف :(
حسناً، في الواقع لم أكن أحتاج لذلك، لأن كلمات بها أيضاً تعبيرات لامدا (lambda expressions)، وهي طريقة لكي أعرف دالة بلا اسم في المكان الذي أريد فيه قيمة تعبر عن دالة.
أي أنه بدلا من "اطبع كلهم(م، الدالة زوجي)" كان يمكن أن أقول:
هذه هي صيغة الـ Lambda expression :
λ متغيرات: تعبير ينتج منه قيمة
ومعناها "الدالة التي تأخذ هذه المتغيرات كعوامل وترجع بقيمة هذا التعبير". مثلاً λ س: س+1 هي الدالة التي لو أخذت س تعود بـ س+1.
(لكي تكتب علامة لامدا في محرر كلمات اضغط زر Ctrl + L، لو كنت تستخدم محرراً آخر يمكنك إدخال رمز ^ بدلاً من لامدا)
في مثال "كلهم" قد مررت للدالة "كلهم" دالة أخرى، هي "الدالة التي لو أخذت أ تعود بالقيمة باقي.قسمة(أ،2)=0"، وهو نفس الدور الذي تقوم به الدالة زوجي -- التي لم نعد نحتاج إليها.
هل تريد أن تتأكد أن المصفوفة م لا تحتوي صفراً؟ بسيطة:
نحن هكذا نحاول أن ندخل بكلمات إلى عصر جديد: عصر الـfunctional programming.
أليس هذا صعباً على الأطفال؟ من يدري؟ نحن لم نجرب بعد. وعلى كل حال إن ظهر أن تلك الإمكانية صعبة فلا بأس: يمكننا أن نتركها في اللغة لكن لا نلزم الأطفال بتعلمها، وباقي اللغة متاحة لهم كما هي. ومن أراد من الكبار (أو الأطفال القادرين) أن يتعلمها فهي موجودة.
الدوال التي تأخذ دوالاً أخرى كعوامل تسمى higher order functions. مثال آخر لمثل هذه الدوال هو الدالة تناظر:
هذه الكود سوف تطبع على الشاشة [2، 4، 6، 8] لأن تناظر تأخذ مصفوفة ودالة، وتعود بمصفوفة أخرى مليئة بقيم المصفوفة الأولى بعد تطبيق الدالة على كل منها. أي أن كل قيمة في المصفوفة القديمة لها قيمة مناظرة لها في المصفوفة الجديدة.
مثال آخر هو الدالة اختزال :
الكود السابقة سوف تطبع على الشاشة القيمة 10، لأن اختزال تأخذ مصفوفة ودالة، ثم تقوم بطبيق الدالة "بين العناصر" كأني في المثال السابق حسبت 1+2+3+4. طبعاً كان يمكنني أن أقدم دالة ضرب بدلاً من الجمع لأحسب حاصل ضرب الأعداد في المصفوفة) أو دالة max لأحسب أكبر قيمة في المصفوفة..أو...أو...
الأسم "تناظر" هو ما أطلقته - في محاولة للتعريب - على الدالة المعروفة بإسم map، والدالة "اختزال" هي reduce.
ربما تكون قد سمعت عن MapReduce. إنها تكنولوجياً مبني عليها كثير من التطبيقات في شركات مثل:
هل تريد أن نبني جوجل خاصة بنا في مجتمعنا؟ لغة كلمات بها البذور العلمية لذلك لغرسها في الأطفال.
إجراء ترحيب( ): اطبع "مرحباً بك" نهاية دالة مجموع (أ ، ب): ارجع ب: أ + ب نهاية س = الإجراء ترحيب ص = الدالة مجموع
سوف تجد في المتغير س كائناً object يسمح لي باستدعاء الإجراء 'ترحيب' متى أردت. وكذلك ص يحمل وسيلة لاستدعاء الدالة 'مجموع' استدعيهما هكذا:
س : تنفيذها ( ) ب = ص : تنفيذها (5، 10)
السطر الأول يطبع الترحيب على الشاشة، والسطر الثاني يضع القيمة 15 في المتغير ب.
لماذا قلنا "س: تنفيذها( ) " في أول سطر بينما قلنا "ب = ص: تنفيذها(...)" في الثاني؟ لأن س تعبر عن إجراء بينما ص تعبر عن دالة.
الآن ما فائدة هذا الاسلوب في إيجاد قيم تعبر عن الإجراءات والدوال؟ هيا نضرب مثلاً ظريفاً:
دالة كلهم (المصفوفة ، الاختبار) : لكل أ من 1 إلى عدد (المصفوفة) : إذا ليس الاختبار : تنفيذها (المصفوفة [أ]) : ارجع ب: خطأ تم تابع ارجع ب: صحيح نهاية دالة زوجي (ر) : ارجع ب: باقي.قسمة (ر، 2) = 0 نهاية م = [2 ، 8 ، 6 ، 12] اطبع كلهم (م، الدالة زوجي)
ماذا فعلنا؟ الدالة كلهم تأخذ مصفوفة ودالة اخرى اختبارية (تعود بالقيمة صحيح أو خطأ)، وتقوم بتطبيق الدالة على كل قيمة في المصفوفة، بحيث لو عادت تلك الدالة بـصحيح لكل القيم، تعود الدالة الأم أيضاً بـصحيح، وإلا عادت بـخطأ.
والآن لم تعد تحتاج كتابة هذا الـ loop مرة أخرى للتأكد أن شرطاً ما ينطبق على كل القيم في مصفوفة!
الأجمل من هذا أن كلمات سوف يكون بها مكتبة جاهزة فيها الدالة كلهم، بالإضافة لدوال أخرى شبيهة هي بعضهم، ليس.كلهم، كلهم.ليسوا ، بحيث يكون اختبار القيم في المصفوفات بسهولة كتابة سطر واحد في كثير من الأحيان.
لحظة...سطر واحد؟ ألم أضطر لكتابة الدالة زوجي في المثال السابق؟ هذا يجعل الموضوع يأخذ أكثر من سطر واحد للأسف :(
حسناً، في الواقع لم أكن أحتاج لذلك، لأن كلمات بها أيضاً تعبيرات لامدا (lambda expressions)، وهي طريقة لكي أعرف دالة بلا اسم في المكان الذي أريد فيه قيمة تعبر عن دالة.
أي أنه بدلا من "اطبع كلهم(م، الدالة زوجي)" كان يمكن أن أقول:
اطبع كلهم (م، λ أ : باقي.قسمة (أ، 2) = 0)
هذه هي صيغة الـ Lambda expression :
λ متغيرات: تعبير ينتج منه قيمة
ومعناها "الدالة التي تأخذ هذه المتغيرات كعوامل وترجع بقيمة هذا التعبير". مثلاً λ س: س+1 هي الدالة التي لو أخذت س تعود بـ س+1.
(لكي تكتب علامة لامدا في محرر كلمات اضغط زر Ctrl + L، لو كنت تستخدم محرراً آخر يمكنك إدخال رمز ^ بدلاً من لامدا)
في مثال "كلهم" قد مررت للدالة "كلهم" دالة أخرى، هي "الدالة التي لو أخذت أ تعود بالقيمة باقي.قسمة(أ،2)=0"، وهو نفس الدور الذي تقوم به الدالة زوجي -- التي لم نعد نحتاج إليها.
هل تريد أن تتأكد أن المصفوفة م لا تحتوي صفراً؟ بسيطة:
اطبع كلهم.ليسوا ( م ، λ أ : أ = 0 )
نحن هكذا نحاول أن ندخل بكلمات إلى عصر جديد: عصر الـfunctional programming.
أليس هذا صعباً على الأطفال؟ من يدري؟ نحن لم نجرب بعد. وعلى كل حال إن ظهر أن تلك الإمكانية صعبة فلا بأس: يمكننا أن نتركها في اللغة لكن لا نلزم الأطفال بتعلمها، وباقي اللغة متاحة لهم كما هي. ومن أراد من الكبار (أو الأطفال القادرين) أن يتعلمها فهي موجودة.
الدوال التي تأخذ دوالاً أخرى كعوامل تسمى higher order functions. مثال آخر لمثل هذه الدوال هو الدالة تناظر:
م = [ 1 ، 2 ، 3 ، 4 ]
اطبع تناظر ( م ، λ أ : أ × 2 )
هذه الكود سوف تطبع على الشاشة [2، 4، 6، 8] لأن تناظر تأخذ مصفوفة ودالة، وتعود بمصفوفة أخرى مليئة بقيم المصفوفة الأولى بعد تطبيق الدالة على كل منها. أي أن كل قيمة في المصفوفة القديمة لها قيمة مناظرة لها في المصفوفة الجديدة.
مثال آخر هو الدالة اختزال :
م = [ 1 ، 2 ، 3 ، 4 ]
اطبع اختزال ( م ، λ أ ، ب : أ + ب )
الكود السابقة سوف تطبع على الشاشة القيمة 10، لأن اختزال تأخذ مصفوفة ودالة، ثم تقوم بطبيق الدالة "بين العناصر" كأني في المثال السابق حسبت 1+2+3+4. طبعاً كان يمكنني أن أقدم دالة ضرب بدلاً من الجمع لأحسب حاصل ضرب الأعداد في المصفوفة) أو دالة max لأحسب أكبر قيمة في المصفوفة..أو...أو...
الأسم "تناظر" هو ما أطلقته - في محاولة للتعريب - على الدالة المعروفة بإسم map، والدالة "اختزال" هي reduce.
ربما تكون قد سمعت عن MapReduce. إنها تكنولوجياً مبني عليها كثير من التطبيقات في شركات مثل:
- Yahoo
- Microsoft
هل تريد أن نبني جوجل خاصة بنا في مجتمعنا؟ لغة كلمات بها البذور العلمية لذلك لغرسها في الأطفال.
الأحد، 18 نوفمبر 2012
عن كون كلمات لغة للأطفال، ولماذا لا تكون لغة احترافية
هناك أكثر من شخص تحدث معي عن سبب إصراري أن تكون لغة كلمات لغة تعليمية وليست لغة لعمل برامج احترافية مثلها مثل Java, Python, ...الخ.
هذا المقال سأقسمه إلى ثلاثة أجزاء:
- الأسباب اللي تدعو لـ"حرفنة" كلمات.
- ردي على بعض هذه الأسباب
- متطلبات تحويل كلمات إلى لغة احترافية، لكي يكون الحوار واقعياً ويفهم القاريء الموضوع بالضبط.
الرأي الآخر: لماذا لا تجعلها احترافية؟
من الأسباب التي تدعو لجعل كلمات لغة احترافية:
- قد يكون هناك عائقاً نفسياً يمنع البعض من استخدام لغة للأطفال أو المبتدئين.
- ماذا سيفعل الأطفال (أو الكبار المبتدئين) بعد تعلم كلمات إن أرادوا عمل برامج احترافية؟
- ماذا عن حلم البرمجة باللغة العربية في كل مكان؟
1- لن يحب أحد أن يستخدم لغة للمبتدئين: هذا جانب اجتماعي/تسويقي. هناك فئة من المبرمجين لا تحب إلا ما هو "قوي" و"احترافي". وهذا قد يدفع البعض لعدم استخدام كلمات لأنها "لعبة". هناك جانب آخر أجتماعي هو أن بعض العرب للأسف لا يرى أنه هناك منتج جيد يمكن أن يخرج من عقل مبرمج عربي، وبعض من هؤلاء سيظنون أنني جعلت كلمات للأطفال لأخفي عيوبها أو ليكون لدي عذر جاهز لأي ثغرة في اللغة: أنها للاطفال.
2- ماذا سيفعل الأطفال (أو الكبار المبتدئين) بعد تعلمها؟ هذا سؤال معقول. هب أن شخصاً تعلم كلمات ثم أراد أن يصنع برامجاً كبيرة أو تجارية، هل سيجب عليه أن يتعلم لغة برمجة أجنبية؟ إن كنت أقول أنني صنعت كلمات لرفع حاجز اللغة الذي يعوق تعلم البرمجة، فلماذا لا أرفع أيضاً (أو بتعبير أدق: أساعد في رفع) حاجز اللغة الذي يعوق البرمجة الاحترافية؟
3- ماذا عن تحقيق حلم البرمجة باللغة العربية؟ هذا جانب اجتماعي أيضاً: لو ظهرت لغة برمجة عربية احترافية، ألن يؤدي هذا لشعور بالفخر في سائر أنحاء الوطن العربي، وأن يزداد العرب ثقة في قدرتهم على النهوض بأمتهم، وأن يكون شيئاً جميلاً على العموم؟
الرأي الخاص بي: لماذا لم أجعلها كذلك
بالنسبة لجانب أن البعض سيراها لعبة: لقد تعلمت البرمجة على كمبيوتر صخر وأنا طفل، وكنت أبرمج
لأستمتع بوقتي قبل أن أعرف بوجود كلية اسمها "حاسبات" أو وظيفة اسمها "مطور
برامج". كلمات بدأت لأقدم نفس الفرصة لأطفال اليوم، ولم تصنع لتكون لغة احترافية.
بالنسبة لتقديم أداة لمن تعلم كلمات لكي يصنع برامجاً أكبر: كما قلت، سؤال
معقول. لكن رفع حاجز اللغة للبرمجة الاحترافية يحتاج لجهد أكبر بكثير من
صنع لغة برمجة فحسب. يحتاج مكتبات libraries للرسومات والوب وقواعد
البيانات. يحتاج ترابطاً مع اللغات الأخرى، يحتاج توثيقاً كبيراً، يحتاج
متابعة وتصليح للعيوب باستمرار، يحتاج وسيلة لتقديم الدعم الفني (ولو في
صورة منتديات) والأهم من هذا: يحتاج قسم تسويق يعمل ليل نهار لجذب الشركات
والمبرمجين المستقلين للتطوير بكلمات وإضافة مكتبات لها.
وهذا ما لا أستطيع أن أقوم به حالياً. ما أستطيع أن أقوم به هو تطوير اللغة نفسها، وهو ليس أمراً سهلاً حتى للغة مبتدئين.
ربما هذا حلم يحتاج لمساهمة من المجتمع كله. فليصنع الناس لغات برمجة عربية أخرى، تعليمية واحترافية وتجريبية. كلمات - لمن لا يعرف - مفتوحة المصدر: يمكن لأي مبرمج أن يدرس الكود ويعرف كيف كتبت. يمكن للمجتمع إن أراد أن يتعلم منها ويصنع مثلها أو أفضل.
الجزء الأخير: الخطوات المطلوبة لتكون كلمات احترافية
(الحديث هنا تكنولوجي وليس اجتماعي، لن أتحدث عن التسويق أو الدعم الفني...الخ ولكن عن تطوير اللغة نفسها).
أولاً: كلمات في صورتها الحالية لغة قوية جداً. فيها مثلاً هذه الإمكانيات:
- tail call elimination
- destructuring
- lambda expressions - في الإصدارة القادمة
- green threads
- CSP channels
وهي إمكانيات معظمها لا يوجد في ++C، ولا بايثون، ولا جافا. (في حالات معينة مثل CSP يمكن تطعيم تلك اللغات بمكتبات خارجية لتقديم هذه الإمكانيات، لكن في حالات مثل tail calls لا يمكن).
لكن على الجانب الآخر، اللغات الأخرى تقدم تنفيذا سريعاً للبرامج، تقدم garbage collection متقدم عن كلمات (ماعدا ++C التي لا تحب مثل هذه الرفاهيات)، تقدم مكتبات لأي شيء تريده، تقدم ضماناً معقولاً لخلو المترجم والآلة الافتراضية من الأخطاء، وتقدم خاصية استدعاء دوال خارجية [بايثون تقدم ctypes لاستدعاء إجراءات مكتوبة بالسي، جافا تقدم JNI لنفس السبب، سي شارب تقدم P/Invoke، وهكذا).
كلمات تحتاج إذاً، لكي تكون أقرب للاحترافية:
- تطوير الآلة الافتراضية الخاصة بها (وهي من تصميمي واسمها SmallVM) لتكون أسرع وبجامع مهملات أفضل. أو كتابة نسخة من كلمات تعمل على ألة افتراضية موجودة.
- ضبط إمكانية FFI الخاصة بها (وهي الخاصية التي تكافيء JNI/ctypes المذكورة بأعلاه). الخاصية موجودة بالفعل في كلمات لكنها تحتاج لاستكمالها.
- إصلاح الكثير من الثغرات والنواقص الموجودة
- صنع خاصية multiplexing over threads، ولو تم صنع هذه الخاصية فستكون ميزة نادرة لكلمات، لا توجد إلا في لغات مثل Google Go أو Erlang
- صنع بعض المكتبات الأساسية مثل web, database, networking
- عمل كل هذا بدون التأثير على سهولة تعلم اللغة، أو ملاءمتها للأطفال، أو جمالها [ربما يتطلب هذا فصل اللغة إلى لغتين واحدة للاطفال والأخرى احترافية، لكن بنفس الـsyntax تقريباً ونفس المكتبات].
بعض هذه الإمكانيات يجري العمل فيه فعلاً (مثلاً أعمل حالياً في خاصية multiplexing)، والبعض مؤجل للمدى الطويل، والبعض لا أدري إن كنت سأقوم به فعلاً أم لا. من يعلم؟ هؤلاء الذين يطلبون لغة احترافية، ربما يحصلون عليها ذات يوم.
Labels:
arabic-posts,
kalimat,
programming,
society
الجمعة، 16 نوفمبر 2012
Solving an ACM problem with Kalimat (part 2)
- هذا المقال تكملة للجزء الأول الذي تجده هنا، لكن في الواقع الجزء الثاني يتضمن كل المعلومات المطلوبة ولا تحتاج لقراءة الجزء الأول لتفهمه.
- مسألة الـACM نفسها هنا
كيف نحل هذه المسألة؟ من حسن الحظ أن شرح السؤال نفسه يلمح لنا بالحل!
The skyline vector
should represent the "path" taken, for example, by a bug starting at
the minimum x-coordinate and traveling horizontally and vertically over
all the lines that define the skyline.
يقول لنا البرنامج أن الحل يصف تحركات حشرة تتحرك عبر صف المبان. تعال نتخيل أن هذه الحشرة هي نملة (بدلاً من البقة المذكورة في المسألة). الحركة في الصور التالية من اليسار لليمين:
في البداية ستسير النملة أفقياً حتى تصطدم بجدار بمبنى:
فإن وجدت المبنى ستبدأ في التحرك رأسياً لتتسلقه
إن وجدت نفسها عند سفح مبنى من جديد، فستبدأ في تسلقه، وإن وجدت نفسها عند هضبة فستنزل
في هذه الظروف، تكون النملة دائماً في حالة من أربع: واقفة على الأرض وأمامها مبنى (تحتاج أن تسير إليه)، أو واقفة على سطح مبنى (بدايته أو وسطه) تسير عليه، أو عند سفح مبنى (فتصعده)، أو عند نهاية سطح مبنى، سنسمي هذه الحالة هضبة، (فتهبط).
وكيف تنتقل بين الحالات؟
إن كانت واقفة على الأرض:
- تسير إلى سفح أول مبنى أمامها
إن كانت واقفة على سطح مبنى:
- يمكن أن يكون هناك مبنى يعوق سيرها، في تلك الحالة تسير إلى وجه المبنى العائق ثم تصبح حالتها "عند سفح".
- أو تكون حرة أن تسير لآخر المبنى الذي تقف عليه، وفي تلك الحالة تفعل ذلك وتكون حالتها "على هضبة"
إن كانت عند سفح:
- تصعد لأعلى المبنى، ثم تكون حالتها "على سطح مبنى"
- إن كان هناك سطح مبنى يعوق هبوطها، تنزل إلى سطح ذلك المبنى ثم تصبح حالتها "على سطح مبنى"
- إن لم يكن هناك عائق تنزل إلى الأرض (ص = 0) وتصبح حالتها "على الأرض"
الملخص:
لم يبق سوى كتابة الكود التي تمثل هذا الرسم، ثم نستطيع جميعنا أن نعود إلى البيت ونأكل الساندوتشات التي أعدتها أمهاتنا :)
شيء نلاحظه: نحن نعلم ان المباني المدخلة مرتبة ترتيبا تصاعدياً حسب الحافة اليسرى للمبنى، لذلك حين نبحث عن عوائق افقية لا يوجد معنى لأن نبدأ البحث من أول مبنى، بل نريد البحث من "أول مبنى على يمين النملة"، لذلك سيكون لدينا متغير اسمه "بداية.البحث.الأفقي" يدل على رقم المبنى الذي سنبدأ منه البحث. هذا المتغير سيأخذ أولاً القيمة 1، ثم نحدثه كلما تحركت النملة لليمين.
الآن إلى الكوووود!!
كما نعلم، مجموعة البيانات المدخلة هي مصفوفة من ثلاثيات، مثل [[12، 10، 20]، [15، 8، 22]، [20، 12، 30]]، وكل ثلاثية تعبر عن مبنى [الحافة اليسرى، الارتفاع، الحافة اليمنى]. فلنبدأ بشيء بسيط: دوال قصيرة لاستخراج بيانات كل مبنى مما يجعل البرنامج أسهل في القراءة:
دالة يسار ( مبنى ) : ارجع ب: مبنى [ 1 ] نهاية دالة سطح ( مبنى ) : ارجع ب: مبنى [ 2 ] نهاية دالة يمين ( مبنى ) : ارجع ب: مبنى [ 3 ] نهاية
الآن نرى الإجراء الأساسي لحل المسألة:
بداية.البحث مشترك إجراء إجابة ( صف.المباني ) : بداية.البحث = 1 على.الأرض ( 0 ، 0 ، صف.المباني ) نهاية
ببساطة: بداية البحث (الذي يدل على رقم أول مبنى على يمين النملة) نحددها بواحد، ثم ننادي إجراءاً يعبر عن الحالة المبدئية للنمية (أنها على الأرض). سوف نصنع إجراءاً يعبر عن كل حالة وننتقل بين الحالات عن طريق استدعاء تلك الإجراءات.
ماذا أخذ الإجراء على.الأرض؟ أخذ قيم س، ص، ومصفوفة المباني.
جميل جداً. الآن ننظر للإجراء نفسه:
إجراء على.الأرض(س ، ص ، المباني) :
لكل أ من بداية.البحث إلى عدد(المباني) : إذا يسار(المباني [أ]) > س : س = يسار(المباني[أ]) اطبع س حدث.بداية.البحث(س، المباني) وكل إلى عند.سفح(س، ص، المباني[أ] ، المباني) تم تابع -- إن وصل التنفيذ هنا فمعنى ذلك -- أن النملة على الأرض ولا يوجد -- مبان على يمينها: أي أن الرحلة -- قد انتهت نهاية
الإجراء مكون من جزئين: الجزء الأول (بين لكل...تابع) يبحث عن أول مبنى على يمين النملة، فإن وجده:
- يغير قيمة "س" ليحرك النملة عند سفح المبنى، ويطبع القيمة الجديدة كما هو مطلوب في المخرجات
- ينادي حدث.بداية.البحث(س، المباني) لكي يبحث عن أول مبنى على يمين س الجديدة ويجعل رقم هذا المبنى هو بداية.البحث
- ينفذ السطر وكل إلى عند.سفح (____ ) ويعطيه بعض القيم، مما يجعل البرنامج الآن في حالة جديدة.
ما معنى وكل إلى؟ انها تجعل السطر من "استدعاء إجراء" إلى "توكيل لإجراء". ما الفرق بينهما؟ في حالة التوكيل فإنه قبل استدعاء عند.سفح(...) سوف يتم أولاً حذف الstack frame الخاصة بـ على.الأرض( ) من الذاكرة، وهذا طبيعي لأن هذا الجزء من البرنامج لا نحتاج أن نرجع إليه.
الآن نرى عند.سفح:
إجراء عند.سفح ( س ، ص ، مبنى ، المباني ) : ص = سطح ( مبنى ) اطبع ص وكل إلى عند.سطح ( س ، ص ، مبنى ، المباني ) نهاية
إذا كانت النملة عند سفح مبنى، فإنها تتسلقه (بتغيير قيمة ص وطباعتها)، ثم توكل سائر العمل إلى الحالة الجديدة: عند.سطح
سهلة دي مش كدة؟
إجراء عند.سطح(س، ص، مبنى، المباني) : لكل أ من بداية.البحث إلى عدد(المباني) : م = المباني [أ] -- لو وجدنا مبنى خارجاً تماماً عن حدود المبنى الحالي، -- فكل المباني التي تليه هي الأخرى خارجة عن الحدود -- وبالتالي لا داع للاستمرار في البحث إذا يسار(م) > يمين(مبنى) : اذهب إلى نهاية.البحث
-- هل م أعلى من المبنى الذي تقف عليه النملة؟ إذا سطح(م) > سطح(مبنى) : -- في هذه الحالة فهو عقبة. هيا نتحرك إلى سفحه س = يسار (م) اطبع س حدث.بداية.البحث(س ، المباني) وكل إلى عند.سفح(س، ص، م، المباني) تم تابع علامة نهاية.البحث -- إن وصلنا هنا ولم نجد شيئاً، نسير إلى نهاية المبنى الحالي س = يمين(مبنى) اطبع س حدث.بداية.البحث(س، المباني) وكل إلى عند.هضبة( س ، ص ، مبنى ، المباني) نهاية
لا تنزعج! الكود أبسط مما يبدو عليها. هي ببساطة تقوم بالآتي:
1- نفذ لكل مبنى م في المباني التي على يمين النملة:
- لو كان يسار م أكبر من يمين المبنى الذي نقف عليه، إذا فكل المباني بعيدة ولا توجد عقبات. سوف نذهب للخطوة 2
- لو كان الأمر غير هذا، فقد وجدنا مبنى يقطع مبنانا! لو كان أعلى من مبنانا أيضاً فيجب أن نصل إلى سفحه. حرك س إلى سفح المبنى، واطبعها، وانتقل لحالة عند.سفح
لو كنت لاتزال تجد صعوبة، انظر إلى الصور مرة أخرى.
الآن نصل إلى عند.هضبة:
إجراء عند.هضبة(س، ص، مبنى، المباني) : أعلى.عقبة = لاشيء لكل أ من 1 إلى عدد(المباني) : م = المباني[أ] إذا م <> مبنى وأيضا يمين(م) > س وأيضا يسار(م) < س : -- لقد وجدنا مبنى يقطع مبنانا -- وهو بالتأكيد ليس أعلى منه لأنه لو كان أعلى -- لكنا عليه بدلا من المبنى الحالي -- لو كنا مازلنا في بداية البحث، نعطي -- قيمة مبدئية للمتغير أعلى.عقبة إذا أعلى.عقبة = لاشيء : أعلى.عقبة = م تم -- سوف نختار أعلى مبنى فيهم لنهبط إليه إذا سطح(م) > سطح(أعلى.عقبة): أعلى.عقبة = م
تم تم تابع
إذا أعلى.عقبة = لاشيء : ص = 0 اطبع ص وكل إلى على.الأرض(س، ص، المباني) وإلا : ص = سطح(أعلى.عقبة) اطبع ص وكل إلى عند.سطح(س، ص، أعلى.عقبة، المباني) تم نهاية
مرة أخرى: الأمر أبسط مما يبدو عليه. الدالة جزءان:
الجزء الأول بين "لكل...تابع" يبحث عن أعلى مبنى يحتوي النقطة س التي تقف فيها النملة (يمينه أكبر من س ويساره اقل منها). لأن هذا الشرط ينطبق على المبني الحالي الذي تقف النملة عليه؛ لابد أن نضع جزءاً من الشرط يتأكد أن م هو مبنى مختلف عن المبنى الحالي.
الجزء الأول بين "لكل...تابع" له دور آخر: من بين كل المباني التي تحتوي س، فإنه يختار أعلاها. هذا يتم عن طريق ثلاثة أجزاء:
- خارج الـloop، يجعل قيمة المتغير أعلى.عقبة تساوي لاشيء.
- داخل الـloop، يعطي هذا المتغير قيمة أولية هي أول مبنى يصلح يجده، وذلك عن طريق الشرط إذا أعلى.عقبة = لاشيء :... هذا الجزء يتم تنفيذه مرة واحدة فقط.
- داخل الـloop أيضاً، يتم كل مرة مقارنة م بأعلى عقبة، لحساب قيمة max في المتغير أعلى.عقبة بالطريقة المعروفة.
لو كان هناك قيمة للمتغير أعلى.عقبة، فهناك إذاً عقبة أمام نزولنا. بدلاً من النزول للأرض ننزل إلى سطح تلك العقبة (المبنى) ونغير الحالة.
أخيراً هذا هو الإجراء حدث.بداية.البحث
إجراء حدث.بداية.البحث (س، المباني) : لكل أ من بداية.البحث إلى عدد( المباني ) : إذا يسار (المباني [أ]) > س : بداية.البحث = أ اذهب إلى النهاية تم تابع علامة النهاية نهاية
الإجراء يستخدم القيمة القديمة لـ بداية.البحث، حتى يجد أول مبنى على يمين النملة (يمينه أكبر من س)، وهنا يسجل رقم ذلك المبنى في بداية.البحث ويخرج.
هل يعمل البرنامج؟ القيم المطبوعة هي نفس النتيجة المكتوبة في موقع المسألة (ولكني لم أختبره على مدخلات أخرى)
يمكنك أن تختبره أنت إن أردت! الكود كاملةً تجدها هنا:
-- هذا البرنامج حل لمسألة Skyline problem من مسائل الـACM -- تجد المسألة هنا: http://uva.onlinejudge.org/external/1/105.html -- اختبارات() حل.المسألة ( ) إجراء حل.المسألة ( ) : صف.المباني = [ ] ملف.المدخلات = افتح.ملف ( "input.txt" ) كرر مادام ليس ملف.المدخلات : منته ( ) : س = ملف.المدخلات : اقرأ.سطر ( ) الثلاثية = تفصيص ( س ، " " ) الثلاثية [ 1 ] = كعدد ( الثلاثية [ 1 ] ) الثلاثية [ 2 ] = كعدد ( الثلاثية [ 2 ] ) الثلاثية [ 3 ] = كعدد ( الثلاثية [ 3 ] ) صف.المباني = صف.المباني + [ الثلاثية ] تابع اغلق.ملف ( ملف.المدخلات ) إجابة ( صف.المباني ) نهاية بداية.البحث مشترك إجراء إجابة ( صف.المباني ) : بداية.البحث = 1 على.الأرض ( 0 ، 0 ، صف.المباني ) نهاية بداية.البحث مشترك إجراء على.الأرض ( س ، ص ، المباني ) : لكل أ من بداية.البحث إلى عدد ( المباني ) : إذا يسار ( المباني [ أ ] ) > س : س = يسار ( المباني [ أ ] ) اطبع س حدث.بداية.البحث ( س ، المباني ) وكل إلى عند.سفح ( س ، ص ، المباني [ أ ] ، المباني ) تم تابع -- إن وصل التنفيذ هنا فمعنى ذلك -- أن النملة على الأرض ولا يوجد -- مبان على يمينها: أي أن الرحلة -- قد انتهت نهاية إجراء عند.سفح ( س ، ص ، مبنى ، المباني ) : ص = سطح ( مبنى ) اطبع ص وكل إلى عند.سطح ( س ، ص ، مبنى ، المباني ) نهاية إجراء عند.سطح ( س ، ص ، مبنى ، المباني ) : -- اطبع "سطح" لكل أ من بداية.البحث إلى عدد ( المباني ) : م = المباني [ أ ] -- لو وجدنا مبنى خارجاً تماماً عن حدود المبنى الحالي، -- فكل المباني التي تليه هي الأخرى خارجة عن الحدود -- لاحظ أن الأمر التالي غير مختوم بكلمة "تم" بل -- الأمر كله سطر واحد إذا يسار ( م ) > يمين ( مبنى ) : اذهب إلى نهاية.البحث -- هل م أعلى من المبنى الذي تقف عليه النملة؟ إذا سطح ( م ) > سطح ( مبنى ) : -- في هذه الحالة فهو عقبة. هيا نتحرك إلى سفحه س = يسار ( م ) اطبع س حدث.بداية.البحث ( س ، المباني ) وكل إلى عند.سفح ( س ، ص ، م ، المباني ) تم تابع علامة نهاية.البحث -- إن وصلنا هنا ولم نجد شيئاً، نسير إلى نهاية المبنى الحالي س = يمين ( مبنى ) اطبع س حدث.بداية.البحث ( س ، المباني ) وكل إلى عند.هضبة ( س ، ص ، مبنى ، المباني ) نهاية إجراء عند.هضبة ( س ، ص ، مبنى ، المباني ) : أعلى.عقبة = لاشيء لكل أ من 1 إلى عدد ( المباني ) : م = المباني [ أ ] إذا م <> مبنى وأيضا يمين ( م ) > س وأيضا يسار ( م ) < س : -- لقد وجدنا مبنى مختلف يقطع مبنانا -- وهو بالتأكيد ليس أعلى منه لأنه لو كان أعلى -- لكنا عليه بدلا من المبنى الحالي -- لو كنا مازلنا في بداية البحث، نعطي -- قيمة مبدئية للمتغير أعلى.عقبة إذا أعلى.عقبة = لاشيء : أعلى.عقبة = م تم عقبة2 = م -- سوف نختار أعلى مبنى فيهم لنهبط إليه إذا سطح ( عقبة2 ) > سطح ( أعلى.عقبة ) : أعلى.عقبة = عقبة2 تم تم تابع إذا أعلى.عقبة = لاشيء : ص = 0 اطبع ص وكل إلى على.الأرض ( س ، ص ، المباني ) وإلا : ص = سطح ( أعلى.عقبة ) اطبع ص وكل إلى عند.سطح ( س ، ص ، أعلى.عقبة ، المباني ) تم نهاية إجراء حدث.بداية.البحث ( س ، المباني ) : لكل أ من بداية.البحث إلى عدد ( المباني ) : إذا يسار ( المباني [ أ ] ) > س : بداية.البحث = أ اذهب إلى النهاية تم تابع علامة النهاية نهاية دالة يسار ( مبنى ) : ارجع ب: مبنى [ 1 ] نهاية دالة سطح ( مبنى ) : ارجع ب: مبنى [ 2 ] نهاية دالة يمين ( مبنى ) : ارجع ب: مبنى [ 3 ] نهاية
الخميس، 15 نوفمبر 2012
Solving an ACM problem with Kalimat
هذه هي المسألة التي يتحدث عنها المقال، اقرأها جيداً ثم تعال وأكمل القراءة :)
شكل مبدئي للحل
البرنامج يقرأ ملفاً به عدد من السطور، كل سطر هو مجموعة من الأرقام تفصل بينها مسافات، وكل ثلاثة أرقام متتالية تعبر عن مبنى في المدن التي تتعامل معها المسألة. إذاً فلنبدأ بقراءة ملف المدخلات وتقسيم كل سطر إلى ثلاثيات
يعتمد هذا البرنامج على مكون لم نكتبه بعد: الدالة إجابة التي تحسب لنا الحل المطلوب. لكن قبل هذا نريد أن نختبر البرنامج ونتأكد أن الخطة العامة تسير كما ينبغي. من أجل ذلك سوف نكتب دالة "إجابة" قصيرة جداً:
عظيم! يمكننا الآن تشغيل البرنامج (بعد التأكد من وجود ملف input.txt به مثال للمدخلات الصحيحة كما في صفحة المسألة).
في الواقع حين جربت تشغيل البرنامج وجدت خطأ...ليس في البرنامج بل في كلمات نفسها! وجدت المفسر يقول لي "استدعاء الإجراء أو الدالة بعدد غير مناسب من القيم المرسلة" وقصده على التعبير ملف.المدخلات: منته( ) ، يبدو أنه كان يتوقع عدداً أكبر من العوامل.
هل ينفع هذا؟ يبدو أن كلام المشككين صحيح: العرب لا يستطيعون عمل لغات برمجة. لماذا لا يرسل أحدكم رسالة بريدية غاضبة لمصمم اللغة يؤنبه على إهماله؟ :(
القصد، قمت بتصحيح الخطأ وإعادة تنفيذ البرنامج:
حسناً! نحن نقرأ المدخلات بصورة صحيحة، ويبقى أن نحل المسألة. هل سنقدر على هذا؟ وسؤال آخر: هل سيعمل الحل بسرعة؟ لاحظ أن كلمات أبطأ بكثير من لغة مثل سي++. هذه لغة مصممة للتعليم والرسم بالكمبيوتر والألعاب، وليس لـ"طحن الأرقام". أنا لم أحل المسألة بعد، لذلك فأنا لا أعرف فعلاً إجابة السؤال. سأبدأ الآن في حلها..
اضغط هنا لتقرأ الجزء الثاني
شكل مبدئي للحل
البرنامج يقرأ ملفاً به عدد من السطور، كل سطر هو مجموعة من الأرقام تفصل بينها مسافات، وكل ثلاثة أرقام متتالية تعبر عن مبنى في المدن التي تتعامل معها المسألة. إذاً فلنبدأ بقراءة ملف المدخلات وتقسيم كل سطر إلى ثلاثيات
إجراء حل.المسألة() : صف.المباني = [ ] ملف.المدخلات = افتح.ملف("input.txt") كرر مادام ليس ملف.المدخلات : منته() : س = ملف.المدخلات : اقرأ.سطر() الثلاثية = تفصيص(س ، " ") صف.المباني = صف.المباني + [الثلاثية] تابع اغلق.ملف(ملف.المدخلات) اطبع إجابة(صف.المباني) نهاية
يعتمد هذا البرنامج على مكون لم نكتبه بعد: الدالة إجابة التي تحسب لنا الحل المطلوب. لكن قبل هذا نريد أن نختبر البرنامج ونتأكد أن الخطة العامة تسير كما ينبغي. من أجل ذلك سوف نكتب دالة "إجابة" قصيرة جداً:
دالة إجابة(صف.المباني) : -- مؤقتا سوف نرجع بالمدخلات كما هي
-- للتأكد أن الخطة العامة صحيحة ارجع ب: صف.المباني نهاية
عظيم! يمكننا الآن تشغيل البرنامج (بعد التأكد من وجود ملف input.txt به مثال للمدخلات الصحيحة كما في صفحة المسألة).
في الواقع حين جربت تشغيل البرنامج وجدت خطأ...ليس في البرنامج بل في كلمات نفسها! وجدت المفسر يقول لي "استدعاء الإجراء أو الدالة بعدد غير مناسب من القيم المرسلة" وقصده على التعبير ملف.المدخلات: منته( ) ، يبدو أنه كان يتوقع عدداً أكبر من العوامل.
هل ينفع هذا؟ يبدو أن كلام المشككين صحيح: العرب لا يستطيعون عمل لغات برمجة. لماذا لا يرسل أحدكم رسالة بريدية غاضبة لمصمم اللغة يؤنبه على إهماله؟ :(
القصد، قمت بتصحيح الخطأ وإعادة تنفيذ البرنامج:
حسناً! نحن نقرأ المدخلات بصورة صحيحة، ويبقى أن نحل المسألة. هل سنقدر على هذا؟ وسؤال آخر: هل سيعمل الحل بسرعة؟ لاحظ أن كلمات أبطأ بكثير من لغة مثل سي++. هذه لغة مصممة للتعليم والرسم بالكمبيوتر والألعاب، وليس لـ"طحن الأرقام". أنا لم أحل المسألة بعد، لذلك فأنا لا أعرف فعلاً إجابة السؤال. سأبدأ الآن في حلها..
اضغط هنا لتقرأ الجزء الثاني
الجمعة، 9 نوفمبر 2012
التاريخ والأشياء الصغيرة
أهوى علم لغات البرمجة (علم مختلف عن الـcompilers). وأفكر دائماً في لغة البرمجة "النموذجية" التي يمكن التعبير بها عما تريد بدون فجوة بين الفكرة في دماغك والكود التي تكتبها. يتفرع من هذا فكرة لغة البرمجة التعليمية التي يمكن لأي شخص أن يدخل منها عالم البرمجة، ولغة البرمجة "الديموقراطية" التي تمكّن أي شخص (صحفي، محامي) أن يكتب برنامجاً في مجال تخصصه، وهكذا.
وأقوى سلاح في هذه الرحلة هو التاريخ. وهكذا تجدني أقضي الساعات في القراءة عن لغات البرمجة القديمة منذ الستينات وما بعدها.
..بحثاً عن فكرة عبقرية لكن مفقودة.
ونحن البشر لا نعيش في عصر حديث بالكامل بل خليط من عصور مختلفة. الكرسي الذي تجلس عليه هو نفس الاختراع تقريباً منذ آلاف السنين. لو نظرت في الشارع لوجدث بائع الفاكهة يسير بعربة يدوية كما في العصور الوسطى. نظرية فيثاغورث مفيدة في عصر الفضاء والـGPS مثلما كانت مفيدة في عصرها. ويكفيك جولة عبر القاهرة لترى ما أقول: الانتقال من حي لآخر في القاهرة هو بمثابة انتقال من فترة زمنية لأخرى.
وفي أيام معركة الجمال في الثورة، ابتكر الثوار - وحدهم - طرقاً حربية مشابهة لما كان يفعله الرومان. حائط بشري يمسك دروع طويلة ويزحف بها... Testudo formation
وحين فكرت في تعريب العلوم كنت آخذ "غطسات" في كتب العلوم الرياضية والطبية أيام الحضارة الإسلامية القديمة، لأرى كيف كان يبدو "العلم باللغة العربية"، وإن كان يمكن أن يكون العلم العربي الجديد امتداداً لما سبق وليس علماً مختلفاً تماماً.

وحين كنت اقرأ عن تاريخ أوروبا في العصور الوسطى، كان الكتاب يتحدث عن كيفية ظهور الجامعات في أوروبا، وانها خرجت من شيء يشبه مجالس العلم في الدولة الإسلامية: المعلم الذي يجلس على الحصيرة ويقرأ الكتاب وهو يعلق على كل جملة يقرأها. كيف يمكن تطبيق هذه الفكرة في العصر الحديث؟
كتب التاريخ الأجنبية تهتم كثيراً بالحياة: ماذا كان شكل المنازل في تلك الحقبة التاريخية؟ كيف كان الناس يطبخون؟ ماذا كانت الوظائف وقتها؟ التاريخ الذي أخذته في المدرسة المصرية كان في أغلبه سلسلة من الحكام والمعارك.
والتاريخ أكبر من هذا! وحين نقول "نتعلم من دروس التاريخ" قد يظن الناس أن الدروس ما هي إلا فكرة عامة غير محددة، لكن الأشياء الصغيرة قيمة: من شكل الكرسي إلى شكل الكتاب إلى شكل المطبخ إلى نظرية فيثاغورس. إن التاريخ هو خلاصة التجارب البشرية، ونحن في عصرنا هذا نعيش نتيجة هذه التجارب.
Labels:
arabic-posts,
computer-history,
history,
ideas,
nahda,
thinking
الاشتراك في:
الرسائل (Atom)