السبت، 1 يونيو، 2013

عن اللغة اليابانية (2)

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

المقال طويل بعض الشيء، لكن أعتقد أنه ممتع جداً وأنك سوف تستفيد كثيراً لو قرأته للنهاية.

قصص ومشاهد

 رموز الكانجي بالآلاف، معظمها رموز مركّبة من رموز أصغر. كيف نتذكر تركيب الرموز على بعضها؟ حين بدأت تعلم الكانجي وجدت نفسي أخترع جملاً تذكرني لماذا - مثلاً - رمز "أذن" + رمز "بوابة" = رمز "يسمع". إنه أمر جميل ويجعلني أشعر أنني أقرأ بيتَ شعرٍ صغيراً مع كل حرف أتعلمه.

هناك من نقّح هذا الأسلوب ولم يكتف بجعلها جملاً تذكيرية بل جعلها قصصاً (أو مشاهداً من قصص) مثيرة للخيال، بحيث تصبح الرموز المختلفة هي الشخصيات والكواليس في المشهد، فإن وصفت المشهد رسمت الحرف. هذه الطريقة معروفة بإسم طريقة هِيْسج Heisig method وهناك الكثير ممن يتعلمون اليابانية بها.

سوف نتعلم الآن سوياً بعض رموز الكانجي لأن أفضل طريقة لشرح الأسلوب الجديد هي استخدامه! بعد أن ننتهي من جولتنا عبر الرموز سوف نناقش "الفلسفة التعليمية" من وراء الأسلوب الجديد، ثم نقدم خاتمة.

ملاحظات: (1) القصص في الجزء القادم بعضها من تصميم هيسج نفسه، وبعضها جمعتها من على الإنترنت من أشخاص يتبعون نفس الأسلوب، وبعضها من تصميمي. (2) أنا مازلت مبتدئاً، وقد يكون هناك أخطاء في ما يلي لأي سبب.

جولة عبر الكانجي

هذا الرمز يعني "فم"، وقد يعني أحيانا "فتحة"، مثلما يقول العرب على الفم "ثغر" أحياناً.
هذا الرمز معناه "شمس" أو "يوم". تذكر أنه في الكانجي تصير الدوائر مستطيلات. ألا يرسم الاطفال الشمس بابتسامة؟ هنا نجد دائرة فيها خط مثل الشمس المبتسمة.
هذا الرمز معناه "عين". لو ظلّلت المستطيل الأوسط باللون الأسود لرأيت عيناً مرسومة بطريقة الأنمي اليابانية.
هذا الرمز يعني "أذن". يشبه العين قليلاً لكن حافته السفلى مائلة للأعلى (مثل حافة الأذن) والخطوط المتقاطعة في الركن تشبه شحمة الأذن.
هذا الرمز يعني "حقل الأرز"، مستطيل من الأرض تقسّمه قنوات الريّ. هل تعلم أن كلمة "جدول" (مثل جدول الضرب أو جدول الحصص) مصدرها جدول الماء الذي يروي الأرض؟ كأن الصفحة قد صارت هي أرض تقسمها جداول الماء جيئة وذهاباً.
هذا الرمز معناه "شجرة". واضح طبعاً.
هذا الرمز معناه "طفل"، مثل الطفل الرضيع في عربة الأطفال، وهناك بطانية صغيرة فوقة هي هنا الخط الأفقي في منتصف الرمز؛ رأسه تظهر من خارجها والشكل العام لجسمه واضح من تحتها.
هذا الرمز معناه "امرأة"، تبدو لي كأنها امرأة ارستقراطية ترتدي قبعة كما في الأفلام القديمة.
هذا الرمز معناه "شخص"، وهو واضح على ما أعتقد. حين يأتي هذا الرمز كمكوّن في رموز أعقد يمكن أن يبدو مثل النصف الأيسر من الرموز التالية: 化 休 保
هذا الرمز يمثل الرقم عشرة، مثل الأرقام الرومانية التي ترمز للعشرة بالحرف X. يبدو أن الشعوب القديمة تحب التعبير عن العشرة بالخطوط المتقاطعة.
هذا الرمز يعني "قوة".
هذا الرمز يعني "بوابة"، وهو واضح: البوابة الحديدية التي تفتح وتغلق بالمحاور على اليمين وعلى اليسار.
هذا الرمز يعني "تاج"، لكنه (على ما أعتقد) في أصله الصيني يعني "سقف"، تذكر هذا حين نقوم بتركيبه مع رموز أخرى!
هذا ليس رمزاً مستقلاً لكنه قطعة من رموز أعقد؛ سوف نعتبره يمثل أرجلاً.
هذا أول رمز مركّب نراه، ومعناه "يرى". الأرجل تدل هنا على النشاط، والعين النشطة ترى.
هذا الرمز معناه "قديم". أعلاه رمز الرقم عشرة وأسفله رمز الفم. ألم نقل أن الفم قد يكون أيضاً فتحة؟ الشيء القديم به عشرة ثقوب.
أما هنا فالرمز يعني "مبكر" أو "سريع". شمس وتحتها عشرة، ولو كان موعدنا من شروق الشمس إلى الساعة العاشرة فهو موعد مبكر.
هذا الرمز يعني "أبيض". ألا يقولون أن ضوء الشمس أبيض ومركب من ألوان الطيف السبعة؟ هنا نرى خطاً يخرج من الشمس، شعاع من الضوء الأبيض.
هذا الرمز يعني "مائة". الخط الأفقي في أعلاه هو الرقم واحد بالكانجي، وتحته رمز كلمة "أبيض"، لأنه حينما يبلغ الرجل مائة عام لا يتبقى له سوى شعر قليل (يمثله هنا شعرة واحدة) لونه أبيض.
هذا الرمز معناه "أخ أكبر". كيف يرى الطفل أخاه الأكبر؟ إنه الأخ الذي كثيراً ما ينصحه و ويأخذه في نزهات، لذلك فإن الأخ الأكبر بالنسبة للطفل هو نصائح وتمشية، أي فم وأرجل.
هذا الرمز معناه "أصل"، أو "أساسي"، أو "كتاب". شجرة وهناك علامة على جذرها الذي هو الأصل الذي قد نبتت منه الفروع. قصة أخرى: الكتاب أساسه الورق الذي يصنع من الشجر، والعلامة في الأسفل سببها أننا بدأنا في قطع الشجرة لكي نصنع منها كتاباً.
هذا الرمز معناه "بضاعة"، تخيل سفينة بضائع محملة بالقمح والأرز والسكر، وكل هذه الأفواه هي "المستهلكون" الذين ينتظروت البضاعة بنفاذ صبر.
وهذا الرمز معناه "يهمس"، فم هامس التفّت حوله كل آذان المستمعين وإلا لن يُسمَع ما يقول.
هذا الرمز يعني "رجل"، لأنه يعمل في الحقل بقوة.
هذا الرمز معناه "يعين"، لأنك حين تعينني تضيف عينك إلى عيني وتضيف قوّتك إلى قوّتي.
هذا الرمز معناه "يضيف" أو "يجمع"، والآن تخيل سياسي يقف على المنصة ويلقي خطبة بصوته الجهوري ليكتسب مؤيدين ويضيف قوّتهم إلى قوّتة.
هذا المشهد معناه "يبحث في الأمر" investigate، والمشهد هنا عبارة عن عين فاحصة فوقها شجرة وتحتها الرقم واحد، هذه هي عين المحقق وهو يفحص البصمات تحت شجرة، لأن هذا هو الدليل الوحيد في القضية.
هذا الرمز معناه "يسمع"، الأذن هنا هي حارس يقف عند بوابة السمع؛ فإن أراد الصوت أن يمر من البوابة ليصل للمخ فسوف يمر أولاً على الأذن.
أما هذا الرمز فمعناه "فترة"، والمشهد هنا هو الشمس وهي تشرق وتغرب في تتابع سريع مثل ضيف يمر دخولاً وخروجاً عبر البوابة.
هذا الرمز معناه "وقت الفراغ"، والأن تخيل تلميذاً يذاكر ويرى الشجرة من بعيد من خلال البوابة، وكل حين يقول لنفسه: حين يصير لدي وقت فراغ ساجري عبر هذه البوابة وألعب تحت الشجرة.
هذا الرمز معناه "مازال" أو "ليس بعد"، (مثل كلمة "لسّة" في العامية المصرية التي تتضمن المعنيين). المشهد هنا هو شجرة يوجد غصن صغير في أعلاها، يدل على استمرارية نموها.
هذا الرمز معناه "رخيص" أو "أمان"، والمشهد هو شخص يتخيل عودته إلى بيته، حيث السقف الذي يأويه وزوجته التي تنتظره، والشعور بالأمان.
وهذا الرمز يعني "أخت صغرى". هل صارت امرأة بعد؟ لا ليس بعد.
هذا الرمز يعني "حرف"، لأنه حين يبدأ الطفل في تعلم الكتابة تكون الحروف هي سقف معرفته.
وهذا الرمز معناه مخاطرة، مثل عين تنظر للشمس بدون خوف من النتيجة.
وهذا الرمز معناه "ينجز"، حقل الأرز هنا يمثل نتيجة العمل والجهد، والحقل نفسه فوق الشجرة في مشهد خيالي كأننا نقول "هيا نقطف ثمار جهدنا!".
الرمز هنا يعني "يستريح"، رجل يستريح عند شجرة.
هذا الرمز يعني "برقوق"، وهو يمثل طفلاً يقف أسفل الشجرة منتظراً حتى يسقط البرقوق ليأكله. الا يستحق البرقوق أن يكون هو الثمر الذي نخصص له رمز الطفل تحت رمز الشجرة؟
أما هذا الرمز فيعني "مشمش"، والمشهد هنا هو شخص كسول ينتظر تحت الشجرة فاتحاً فاه، فالمشمش صغير وقد يسقط فيدخل فمه مباشرةً، هكذا يظن.
وهذا الرمز معناه "يُذهَل"، وهناك رجل قد ذُهِل مما رأى فتسلق أقرب شجرة وأخذ يصيح بملء فمه ليخبر الناس بما رآه.
وهذا معناه "ينتصر" أو "يتغلّب على": الرقم عشرة تحته "أخ أكبر"..لو كان معك عشرة من إخوتك الكبار فإنك بالتأكيد ستتغلب على خصمك!

تهانينا! لقد تعلمنا سوياً أربعين من رموز الكانجي في فترة قصيرة جداً، منها ثلاثة عشر رمزاً هم رموز أساسية تُعرف كما هي وسبعة وعشرون ركّبناها عن طريق المشاهد، طريقة سهلة في التذكر وصعبة في النسيان.

أربعون، هل تتخيل؟ لقد قمنا بإنجاز (果) كبير اليوم.

المهم هو التركيب
قد يبدو لأول وهلة أن هذا المقال ما هو إلا تكرار لفكرة "رموز الكانجي هي رسومات"، لكنّ الأمر ليس كذلك:

أولاً: فكرة "رموز الكانجي رسومات" لا تقدّم لنا أسلوباً عملياً يمكن تطبيقه لدراسة الكانجي، وإلا لكان الجميع يتعلمونه بسهولة.

ثانياً: الفكرة نفسها ليست صحيحة. مثلاً تعلّمنا أن مائة هي 百. قل لي: هل نحن هكذا رسمنا المائة؟

ثالثاً: الكانجي بها آلاف الرموز، منها حوالي مائتي رمز أساسيين والباقي تراكيب أعقد تستخدم الرموز السابقة. معنى هذا أن المشكلة ليست في رسم الرمز بل في "التكوين" أو "التركيب". ليست المشكلة في أن شجرة هي 木 بل المشكلة هي كيف نجمع بين رمز "شجرة" ورمز "خروف" ورمز"شمس"...الخ لنكوّن رموزاً أعقد، لهذا قلنا كل هذا الكلام عن القصص والمشاهد.

نقطة جانبية
أليس العلم كله كذلك؟ إن العلوم تركز جداً على علاقات الأشياء ببعضها البعض: البرمجة هي تراكيب من البيانات والإجراءات، والرياضيات تجد فكرة "relation"، وفكرة "function" التي هي حالة خاصة من relation، في أساسها. كل علم ترى فيه مكونات أساسية وتراكيب.

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

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

الخميس، 30 مايو، 2013

A Prolog for my Kalimat

I've tried twice to add program analysis to Kalimat, and each time I had trouble. Program analysis is collecting data about the program to use for IDE features like 'go to definition', autocomplete, 'find usages', and so on.

Basically this operation has 3 parts:
  • Regularly parse the code in the editor windows (for speed most IDEs reparse only the changed parts of the code).
  • Update a program database that holds information like what methods are defined in each class, where is some variable declared,...etc
  • When you need to do some action like 'go to definition', query that database
Let's ignore part #1 and focus on updating and querying the program database. The first time I implemented it the solution was very ad-hoc: I stored things in hashtables, queried them with loops, and the code was very tedious, repetitive, and error-prone.

This was clearly not good, so I decided to use a real database: SQLite is a lightweight database engine that can be easily embedded in other programs, and also has the option to store data in memory instead of on disk. Perfect. In the second iteration the code for 'go to definition' looked something like this:

QSqlQuery q;
q = progdb.q("SELECT defining_token_pos, function_definitions.module_filename "
   "FROM function_definitions JOIN definitions ON definitions.id=function_definitions.def_id AND "
   "definitions.module_filename = function_definitions.module_filename WHERE (definitions.module_filename IN (SELECT imported FROM "
   "module_imports WHERE importer=?) OR definitions.module_filename=?) AND definitions.name in (SELECT lexeme FROM tokens WHERE pos <=? "
   "AND pos + length >=?)", filename, cursorPos, cursorPos, filename);
if(q.next()) { 
   docContainer->OpenOrSwitch(q.value(1).toString());
   ((MyEdit *)currentEditor())->;jumpToPos(q.value(0).toInt()); return;
}

It might look complex but the idea is simple, what the query's trying to say is "Find the filename and position of the function definition that has the same name as the name under the cursor. When looking for a function definition, look in the current module or any module imported by the current module".

This works, but has a lot of drawbacks

1- The query isn't recursive. If the current file imports module A, the IDE will look there for definitions, but if we import 'A', and 'A' imports 'B', the IDE will not look there. We want all modules reachable from the current module to be found.

SQL isn't very friendly with recursion so I probably would've had to implement recursion myself with C++ code.

2- The bigger problem is that the SQL here is too complex. Sure it beats loops and hashtables but it's still big, and that's only for 'go to definition'! How about when I add public and private definitions? namespaces?

What I need is a reasoning system. Luckily there's one: Prolog.

Actually I don't need the full Prolog language; a subset of Prolog has been created to support complex queries (much more complex than SQL), this subset is called Datalog, and it's successfully used in program analysis in many research projects.

I set out to find a nice Datalog implementation for my aims, but didn't find something sufficient: there's an excellent library called BDDBDDB but it's in Java, and there's another one called simply 'Datalog' written in C and Lua that seemed not straightforward to integrate with Kalimat (nb: Kalimat is written in C++/Qt).

Then I looked at open source Prolog implementations like SWI or Ciao, and while very powerful and fast, they didn't seem easy to integrate with a standalone C++ app, especially an app like Kalimat that has to run on both Windows and Linux. I might be wrong but I felt it wasn't easy.

So what did I do? Why, created a new Prolog implementation of course! It's called SmallProlog (and nicknamed 小さい Prolog), specially designed for integration with C++/Qt.

Using Prolog from C++ has never been easier:

PrologEngine engine;
engine.load(prologCode);
engine.call("predicate", arg1, arg2, [](QMap<QString, QVariant> sol){ 
 // do stuff with each solution
});

The expression [ ](QMap<QString,QVariant> sol){ ... } is a lambda expression, a new feature of C++. You define here an anonymous function that gets called whenever the Prolog engine finds a solution. The 'solution' will be a map from variable names to their values.

Under the hood the engine stores facts in a SQLite database, but this time the queries are generated for us from a higher level and more expressive language.

So how does 'go to definition' look now?

usagesOfProc(DefModule,DefPos,UseModule,UsePos):-
   
visibleFrom(UseModule,DefModule),
    procInvokation(UseModule,Name,UsePos),
    proc(DefModule,Name,DefPos,_,_,_)
    .
  
visibleFrom(Mod1, Mod2):-
    visibleFrom2(Mod1,Mod2,[Mod1]).
visibleFrom2(M1,M1,_).
visibleFrom2(M1,M2,Visited):-
    imports(M1,Temp),
    not(member(Temp,Visited)),
    visibleFrom2(Temp, M2,[Temp|Visited]).

The second predicate, called visibleFrom, can take a Kalimat module and give us all the other modules reachable (recursively) from the first module, including itself.

It can also work in the opposite direction: given a module it can give us all modules that 'see' it. The power & elegance of Prolog at work.

The first predicate, called usagesOfProc, takes a module & a position of a function call, and gives us another module and position where the function is defined.

It can also work in the opposite direction: given a function definition, it can give us all files and positions where the function is called.

So when I implemented 'go to definition' I was also implementing 'find usages'; write a feature and get one for free! The power & elegance of Prolog at work.

Aside: I wish the makers of Prolog implementations marketed them as languages for more than industrial and vertical market type applications, and made them trivial to integrate with all types of other languages.

Also, to help myself with debugging, I made a Prolog console where I can query the Kalimat program database live, while the IDE is running:



It's an experiment, and it's still unfinished so I don't know if it'll work as I desire or not, but I'm very excited about it. Aren't you? :)

الأربعاء، 15 مايو، 2013

g4c: Common problems and frequently asked questions

Can I use normal C++ libraries in my g4c application?

Yes, you can use code from C++ libraries, like files, rand( ), strings,... except any code related to the console (cin, cout, getch( ),.....

My program behaves erroneously if I call wait( ) with a large number, like wait(2000) or wait(5000)

There is a problem with the wait function; to wait for a long time you can wait for a short time many times; for example instead of calling wait(2000) you can call wait(50) forty times. Tip: you can create a function to do that for you.

س: ازاي اتغلب على مشكلة الحد الأقصى بتاع 30 sprite؟

ج1: استخدم ذكاءك؛ كل الألعاب القديمة (غزاة الفضاء، باكمان، ماريو...) احتاجت لعدد قليل من الsprites. لاحظ ان رقم 30 هو حد أقصى للأشكال الظاهرة على الشاشة في لحظة معينة
ج2: لو عايز ترسم صورة من غير ما تحركها، ممكن تستخدم copy_sprite_image بدلاً من put_sprite، ودي مالهاش حد أقصى (لكن ما تسمحش بتحريك الصورة اللي رسمتها أو التصادم)

How to clear the screen?

  • Use fill_rect to draw over normal graphics
  • To hide sprites, use hide_sprite (give any numbers as the x, y parameters; they're not important)


 س: (سؤال متقدم) اللعبة بتاعتي بتهنج لو شغلتها من mouse_proc

ج: شغلها من main، لأنه لو الmouse_proc قعدت تشتغل بلا توقف حتعطل الـmessage loop بتاع البرنامج والمستخدم مش حيقدر يعمل فيه أي حاجة ثانية س: بس أنا عايز اشغل اللعبة لما المستخدم يدوس بالماوس على مكان معين ج: لو عايز main تفضل منتظرة حدث معين اعمل متغير بـfalse، خلي الmain شغالة في loop مادام المتغير ده لسة خطأ، وخليه true في الmouse_proc لما تحب اللعبة تشتغل.

ملاحظة: لو ما مريتش بالموقف اللي السؤال ده بيتكلم عنه، تجاهل السؤال والإجابة.

How can I convert a string to a char* in order to use it with text_out?

Learn from this example:

string s = "Hello";
char *c = (char *) s.c_str();
text_out(c, 20, 20);

How can I convert a char * (that I got by using the input( ) function) to a string?

Learn from this example:

char *c = input("Enter your name:", 30, 30);
string s = c;

ملاحظة: لو عايز تقرأ أكثر من قيمة نصية باستخدام دالة input وتحافظ عليهم، لازم تعمل نسخة من كل حاجة تقرأها قبل ما تقرأ اللي بعدها، لأن دالة input دايماً بتقرأ في نفس المكان في الذاكرة، وبالتالي لو ما عملتش نسخ حتلاقي ان كل حاجة قرأتها بقى لها نفس القيمة.

لو قرأت القيمة وحولتها لرقم فكدة تبقى حافظت عليها، لأن الرقم سوف يخزن في مكان مختلف في الذاكرة
لو قرأت القيمة في صورة char * وحولتها لـstring، تبقى حافظت عليها لأن الـstring حيعمل لنفسه نسخة
لو قرأتها char * ومش عايز تحولها لـstring، استخدم strcpy كما في المثال الآتي:

char *c = input("Enter your name:", 30, 30);
char s2[100]; // make sure it's of sufficient size
strcpy(s2, c);
// now use s2

للأسف طريقة انك تعمل array of char بحجم ثابت كبير عشان تشيل فيه نص غير معروف حجمه هي طريقة سيئة، كان ممكن الـg4c تخبرك بعدد الchar التي قد تم قراءتها وتعمل انت dynamic allocation بالحجم ده. يمكن أحل المشكلة دي في إصدارة قادمة.

الاثنين، 11 مارس، 2013

Kalimat: an educational programming language with a twist

I've been working on a language for teaching programming to children. One sentence summary: It looks like the child of QBasic and Google's Go, with influences from other languages.



The  syntax and programming environment are geared towards educational use, but the VM on which programs run (called SmallVM) has support for microthreads, CSP channels, and an FFI. The language itself has things like lambda expressions, a limited form of destructuring, and opt-in tail call elimination.

This article will be divided into two main parts, the first of which discusses Kalimat as an educational language for beginners, and the second shows some of its more advanced features, talks about the implementation, and mentions some ideas about taking the language forwards.

A little background

Kalimat started as an Arabic-based programming language, but I've decided to turn it into a bilingual one; with a compiler switch you can have Arabic or English-based syntax with a corresponding IDE and standard library. I'm doing what I can to make both languages equal citizens, but Arabic still has a higher precedence since the goal of Kalimat is to help the Arab-speaking world learn programming, and to provide a means of "computational empowerment" to non-programmers.

Kalimat was made bilingual because:
  • Often, the novelty of an Arabic-based language dominated the conversation when I wanted to talk about the design and features of the language itself. Having an English version would make it simpler to talk about the technical details.
  • I wanted to interact more with the global PL community, the majority of which are English speakers.
  • To help with scientific studies about teaching programming with PLs in native vs. non-native human language.
  • As a bonus, working with an English version of Kalimat showed me some verbosity in the original syntax which I hadn't noticed since I was too used to the original syntax I had designed.

The language can be downloaded from here, with pre-built English and Arabic versions for Windows. Non-Windows users can check out the source and build it with Qt Creator and the Qt library (version 4.8.x), but they would need to uncomment the following line in both of the files 'kalimat.pro' and 'smallvm.pro' to Enable English syntax/IDE:

#DEFINES+= ENGLISH_PL

Moving on....

Basic syntax

This is a word-count sample in Kalimat:

read "Enter some text:", str 
words = split (str, " ")
result = {}
for word in words:
    if not containsKey (result, word):
        result[word]= 1 
    else:
        result[word]= result[word]+ 1 
    done 
loop 

for pair in result:
    print key pair, " : ", value pair 
loop 

Looks kind of Pythonic, and the code is self-explanatory I think! We have the basics: Simple input and output, iteration, dictionaries (arrays are also supprted), and conditionals.

Here is another quick example:

proc lines (a):
    for i = 1 to a :
        drawLine(random (800), random(600))-(random(800), random(600)), random (16)
        wait (100)
    loop 
end 

lines (200)

In Kalimat a user can define a proc or a func, with the latter being able to return values to the caller (similar to the Sub/Function dichotomy in Microsoft's *-Basic languages). In my opinion this makes the language easier to teach since we can explain procs as 'pieces of code with a name', and worry later about passing parameters and using return values. Experimentation would tell if this was the right decision.

As seen from the drawLine statement, Kalimat has graphics commands that were taken as they are from 80s BASIC, we also have drawPixel, drawCircle, drawRect, drawImage and drawSprite.

We have classes and objects in Kalimat too:

class Point :
    has x, y 
    responds to draw ()
end 

response Point p to draw ():
    drawPixel (x p, y p)
end 

p = new Point having x = 120, y = 150 
p : draw ()

Like the proc/function division, an object can respond to a message sent to it, or it can reply with a value.

The syntax is a little verbose but I have a hypothesis that it would pay off when teaching OOP to beginners. In my brief period of teaching OOP (to college students) I have often found that the syntax of a language like C++ has too many implicit meanings (what 'this' means, what happens in a line like a.b(c)...etc) and that when the students see this syntax they need constant reminding of what it actually represents.

I've tried to make the stuff that happen behind the scene explicit in the syntax, things like 'I'm sending a request to the object, the object shall respond, the response has a reference to the actual object...). When they have fully grasped the semantics the learners can move on to more mainstream languages (or an additional, more streamlined syntax, could be added to Kalimat).

Combining graphics, OOP and Kalimat's sprite engine; we can remake the QBasic classic Gorilla example. The code for that example (and others) is bundled with Kalimat's distribution, or it can be seen here.

Finally, Kalimat has features to help specifically with teaching:
  • The 'Edit' menu has a 'Copy as HTML' feature to help post code in online tutorials and the like. The examples in this blog have been formatted that way (but some minor annoyances in spacing had to be manually corrected; I hope I can fix those annoyances soon).
  • The 'Program' menu has a feature called the monitor which provides an animated trace of a program, while showing the call stack in the 'Variables' tab at the bottom.
  • The 'Test' menu has the option of showing the SmallVM IL generated from source, which could be useful if someone wants to use Kalimat for teaching compilers. It's planned to later add features for visualizing basic blocks and control flow in methods, mainly to help me debug the VM; but could also be used in teaching compilers.
This concludes our brief tour of Kalimat as an educational language, now we move on to concurrency and other more advanced features.

Concurrent processes

Those five forms are the main ingedients for working with processes:

launch procInvokation ()
c = channel ()
send val to c 
receive var from c 
select :
 send 123 to c1 :
   -- statements
 or receive x from c2 :
   -- statements
done

Processes are scheduled internally by the VM and are independent from operating system processes or threads. The launch statement starts a process, the channel() function creates a new channel, send, receive and select statements enable communication between processes using channels as a data exchange/synchronization mechanism.

Both sending and receiving are synchronous (a sending operation blocks until another process is ready to receive from the channel and vice versa), and the select statement takes a set of alternative channel operations and applies the first operation that is ready to run, along with its associated sub-statements; if more than one operation were ready at the same time one operation is chosen randomly from among them.

(If you're familiar with Google Go, then all of this is old news to you).

Why were these features added? Again based on some hypothesis I have about teaching programming. The goals were:
  • To enable children to create games and animated scenes where multiple agents move and behave independently
  • To make GUI programming easier (all GUI widget events are represented by channels, you could model a sequence of GUI interactions with sequential statements: receive some event from channel1, then receive another from channel2...)
  • Since we seem to be entering an age of concurrent programming, it doesn't hurt to have a language where it's easier to teach the concepts of concurrency

I think it's interesting that channels support Kalimat's iteration protocol, so you can say

for someVar in myChannel:

..and have the system iteratively receive data from the channel until it's closed. This feature encompasses the capabilities of something like Python's generators (or yield return from C#) but I think it's more powerful than either of them; for example, from what I've seen it's somewhat cumbersome to use yield to recursively create an iterator for a tree in Python, however in Kalimat it's very natural:

for elem in enumerateTree (t):
    print elem 
loop 

proc enumerateTree (t):
    chan = channel ()
    launch traverseTree (t, chan)
    return chan 
end 

proc traverseTree (t, chan):
    traverse (left t)
    send data t to chan 
    traverse (right t)
end

What we did was a little bit of glue code, then a traditional tree traversal, sending whatever we visit to the channel.

Simple destructuring

We have syntax to test if some given data has a given structure and to extract data from that structure. In this example we'll be testing if a given value is an array, map, or object:

proc showName (x):
    if x ~ [?first, ?last]:
        print first, " ", last 
    else if x ~ {"firstName"=>?x, "lastName"=>?y}:
        print x, " ", y 
    else if x ~ Person having firstName = ?x, lastName = ?y :
        print x, " ", y 
    done 
end

Preceding a variable name by ? extracts the corresponding component into the variable, otherwise the component is tested for equality against the variable (using the same ?var twice destroys the first value, this feature is not really pattern matching/unification). Matching keys in a map cares only about the subset of keys being tested (i.e other key/value pairs could exist and the match would succeed), the same goes for testing fields in objects. Matching on arrays like this x ~ [a, b, c] tests against the exact array count, but x ~ [a, b, c, ...] can successfully match a larger array.

Tail call elimination

The statement delegate to someInvokation() can be used inside a procedure or a function in Kalimat to properly tail-call some routine. This feature was created in case an educator wanted to teach certain styles of programming, and to make the VM extensible (for example to make it possible to support continuations if so desired).

Parser generation

Kalimat has a built-in parser generation engine (this was made with the intention of using Kalimat to teach computer science and not just programming, and to enable the creation of natural language interfaces, text adventure games,...etc by kids).

For example writing this code

rules expression :
 
expression = term:a "+" expression:b => ["+", a, b]
or term:a "-" expression:b => ["-", a, b]
or term 

term = number:a => toNum (a)
or "(" expression:a ")" => a 

number = digit:a number : b => a + b 
or digit 

digit = from "0" to "9" 
 
end

...would provide a function called expression that takes a string and returns a parse tree for simple arithmetic expressions. The capability uses PEG notation with a memoizing packrat parser. Unfortunately the generated parsers can't currently handle left recursion (thus the above grammar actually has a subtle mistake because it treats subtraction as right-associative). I've read the various papers about handling left-recursion in PEG's, but I have yet to understand the techniques :)

A function-plotting sample application that demonstrates this feature is bundled with Kalimat, or could be seen here.

There are two interesting additions that could be made to the parsing engine:
1- Adding the ability to parse any enumerable stream of data, not just a string, and to pattern match against data. This would be like OMeta and its various derivatives.

2- Since channels are enumerable, this would make it possible to parse anything that could be sent to channels: imagine the ability to write grammars for GUI interaction models, sequences of packets from the network, routing web requests, and so on; basically enabling the creation of grammars for things for which we now create state machines.

If features #1 and #2 above were well-implemented I think it would give way to an exciting, highly declarative style of programming.

Implementation

Kalimat code runs on a custom-made VM called SmallVM. It's a simple stack-based machine that runs concurrent processes using an internal scheduler. It currently uses two threads: one for code execution and the other for GUI.

Because Qt does not allow GUI operations to run outside the event handling thread; the GUI thread also has an interpreter instance. A process that needs to do a UI operation migrates to the other interpreter, does its job, then migrate back to the main execution thread. There are plans to have multiple execution threads and to multiplex the execution of processes among them (like Erlang or Go).

An ambitious project would be to hook the VM scheduler to libuv and have the ability to schedule tasks Node.js style but without the callbacks, since the VM would suspend and resume processes automatically.

Performance wise, I could describe SmallVM as "somewhat satisfactory for its intended goals". On my machine, executing fib(30) takes about one second in Python but 3 seconds in Kalimat. On another dual core machine the time for Python is still one second, but for SmallVM it becomes about 1.4 seconds. I have yet to run more scientific benchmarks.

The VM has a simple FFI built using libffi; it supports calling C functions and having callbacks to Kalimat functions. The callback feature is currently still in development since it has a complicating issue: what happens if C code calls a Kalimat procedure, then that procedure waits on a channel until another process sends it something ?

To make the above case work invoking a callback has to run a secondary VM execution cycle, not just run the code of the callback procedure. Even running in multiple threads wouldn't completely solve the problem. The code to handle these cases is already in the VM, but not really tested and is expected to be buggy for now.

This applies to Kalimat in general: I think I might have some good ideas for designing a PL but I'm not so good at implementation. The language has its fair share of bugs and quirks, and now with the English based IDE the quirks have increased (expect to see the occasional untranslated error message or right-to-left dialog box for the time being). However I'm pushing on, and I hope the product keeps getting better over time.

Thanks for reading about my small programming language; I hope something from it got your interest!

الثلاثاء، 26 فبراير، 2013

ما الجديد في كلمات، إصدارة فبراير 2013

بروتوكول للتكرار

تدعم كلمات الآن إمكانية "بروتوكول التكرار"، هذه الميزة تجعل التعامل مع البيانات أسهل ولها قوة خاصة حين تعمل مع إمكانية القنوات. التفاصيل في هذا المقال.


أسرع :)

مرة أخرى نقترب من هدفنا (مضاهاة سرعة لغة بايثون أو التفوق عليها) بالمزيد من التحسينات في أداء برامج كلمات.

نسخة انجليزية

يمكن الآن استخدام كلمات كلغة برمجة انجليزية أيضاً. ليس معنى هذا على الإطلاق أنني تركت فكرة لغة البرمجة العربية! كلمات العربية مازالت هي المنتج الأساسي، لكل النسخة الانجليزية قد يكون لها بعض الفوائد العملية عند الحاجة، مثلاً:
  • استخدامها في تجارب علمية توضح الفرق في سهولة التعليم بين تعليم البرمجة بلغة برمجة عربية ولغة أخرى مشابهة لكن انجليزية، مع تقليل الفوارق الأخرى بين اللغتين قدر الإمكان.
  • الرد على من قد يقول أن كلمات لا يوجد ما يميزها سوى أنها عربية؛ بإظهار مزاياها حتى ولو كانت انجليزية
  • ...وهكذا

النسخة الإنجليزية تستخدم نفس الكود الخاصة بالنسخة العربية، ويتم بناؤها بفتح ملف kalimat.pro وإزالة علامة # في السطر الذي نصه:
#DEFINES += ENGLISH_PL

أرجو ملاحظة أن النسخة الانجليزية ليست مكتملة، وأنه قد يكون بها مشاكل في الإصدارة الحالية

يمكن تحميل أحدث إصدارات كلمات من موقع تطويرها على جوجل كود:
أو من موقع اللغة الرسمي:

ويمكن تعلمها من دليل الاستخدام الذي يمكن تحميله من الرابط التالي، أو من أي من المواد التعليمية الموجودة على موقعها

نتمنى لكم برمجة ممتعة مع كلمات!

الأحد، 17 فبراير، 2013

بروتوكولات التكرار في لغة البرمجة كلمات

مصطلح بروتوكولات التكرار هو محاولة مني لتعريب iteration protocols، وهي إمكانية موجودة في لغات برمجة كثيرة مثل Java, #C، بايثون، وغيرها. (كلمة iteration معناها حرفياً تكرار، لكني لست متأكداً من هذا التعريب وأريد أن أراجعه).

هذه الإمكانية هي التي تسمح لك أن تقول مثلاً في سي شارب:
foreach(int x in p) {
  // code  
}

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

وقد أضفت iteration protocol في كلمات (في نسخة قيد التطوير ولم تصدر بعد، لكن أتمنى طرحها قبل نهاية فبراير)، وهنا أتكلم عن هذه الإضافة. أولاً، صار في كلمات حلقة لكل/في:
 م = [1، 2، 3، 4]
لكل أ في م :
    اطبع أ 
تابع

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

ق = {"حار" => "بارد"، "كثير" => "قليل"، "قوي" => "ضعيف"}
لكل أ في ق :
    اطبع "عكس "، مفتاح أ، " هو "، قيمة أ 
تابع 

بالنسبة للبروتوكول نفسه: لو أردت أن تصمم فصيلة بحيث يمكن المرور على عناصر كائناتها بأمر لكل/في، فستحتاج فصيلتك أن يكون فيها رد (أي method تعود بقيمة) اسمه المعدد ، يعود بكائن خاص تستخدمه حلقة لكل. كيف تستخدمه بالضبط؟ لو قلت مثلاً:

لكل أ في ب: 
    -- أوامر
تابع 

فإن الأمر يتم تحويله داخلياً إلى ما يشبه الآتي:
م = ب : المعدد()
كرر مادام م : تقدم()
    أ = م : القيمة.الحالية()
    -- أوامر
 تابع 

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

لكن هناك شيء خاص بكلمات هنا: القنوات تدعم بروتوكولات التكرار.

هذا شيء مهم جداً، لذلك سأكرره: القنوات تدعم بروتوكولات التكرار!

(إن كنت لا تعرف بعد ما هي القنوات، يمكنك أن تطلع على هذا الجزء من توثيق كلمات الخاص بالبرمجة المتوازية)

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

مثال بسيط على هذا، المرور على عناصر شجرة: تخيل أن لدينا فصيلة اسمها شجرة لها ثلاث خصائص: بيان، يمين، يسار. هذه هي الشجرة الثنائية العادية التي يأخذها طلبة علوم الحاسب. الآن نريد أن نفعل هذا:

لكل أ في تعديد.شجرة(ش):
    ....
تابع
سوف نكتب الآن الدالة تعديد.شجرة (كلمة تعديد هي تعريبي لكلمة enumeration):
دالة تعديد.شجرة(ش):
    ق = قناة()
    شغل تعديد(ش، ق)
    ارجع ب: ق 
نهاية

كما ترى، كل ما تفعله هذه الدالة هو صنع قناة، ثم تشغيل إجراء مواز وتقديم الشجرة الأصلية والقناة له. وظيفة ذلك الإجراء (المسمى تعديد) هو المرور على عناصر الشجرة وإرسال كل ما يمر عليه للقناة:

إجراء تعديد(ش، ق):
    إذا ش <> لاشيء
        تعديد(يسار ش، ق)  
        ارسل بيان ش إلى ق 
        تعديد(يمين ش، ق)
    تم 
نهاية

الشيء الذي يميز هذا الإجراء هو أنه لا يميزه شيء! إنه إجراء tree traversal عادي جداً جداً - مرة أخرى، مثل ما يأخذه طلبة حاسبات - كل ما يفعله هو أنه حين يجد قيمة يرسلها للقناة، ولا يوجد أي شيء عن التعديد أو البروتوكولات، لكن هذا الإجراء هو كل ما تحتاجه للمرور على عناصر الشجرة.

ماذا لو أردت المرور بطريقة مختلفة مثل breadth-first أو ربما postorder؟ غيّر الإجراء الثاني بدون أن تهتم بالبروتوكلات وما إلى ذلك. ماذا لو أردت المرور على عناصر شيء آخر؟ ربما graph؟ استخدم الخوارزميات التي تعرفها، لكن لا تنس إرسال كل عنصر  للقناة :)

توجد إمكانيات مشابهة في لغة سي شارب (أمر yield) وفي لغة بايثون (إمكانية generators) لكني أعتقد أن طريقة كلمات أقوى (المرور على الشجرة مثلاً أعقد في سي شارب/بايثون لأن أمر yield لا يعمل بنفس الطريقة في وجود recursion).

عند تصميم لغة برمجة لا يكفي أن تضع فيها باقة من الإمكانيات، ولكن لابد من التفكير في التكامل بين الإمكانيات المختلفة. أعتقد أن التكامل بين الإجراءات الموازية والقنوات وبروتوكولات التكرار يعطي كلمات قوة خاصة.

الثلاثاء، 29 يناير، 2013

ما يمكن أن يكون

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

يقول Piaget أن المعرفة مثل بناء متعدد الطوابق؛ وكل مستوى جديد ينبني على المستويات السابقة، وأنه حتى إن كان المستوى السابق به ثغرات فكرية إلا أنه ضروري للمستوى الذي يليه، وبالتالي هو مرحلة مهمة في تطور الطفل فكرياً.
____________

ويبدأ المبرمجون في السخرية من لغة Lisp. لديهم حجتان دائماً: انها مليئة بالأقواس، وأنها ليست ناجحة تجارياً. كذلك لغة Prolog لم أر أحداً يتحدث أبداً عن شيء فيها إلا وتساءل: هل تستخدم تجارياً في أي شيء؟

أما أنا حين رأيت تلك اللغة تغير الكثير من تفكيري عن البرمجة: لقد رأيت طريقة قوية جداً للتفكير في البرنامج. ما الذي يهم إن كانت ناجحة تجارياً أم لا؟ أنا أريد مستقبلاً تكون فيه البرمجة كلها بهذا الشكل!
____________

 ورأيت ذات مرة على أحد المنتديات من يقول أن العرب متأخرون في إنتاج علومهم الخاصة، وقدم مثالاً على ذلك هو أن لغة البرمجة العربية كلمات أضعف حتى من الـVisual Basic. الكلام صحيح: كلمات أضعف من الـVB (التي هي أصلاً لغة قوية جداً، قبل أو بعد الـnet.)، لكنها في نفس الوقت مشروع لم يكتمل. لن أطلب من الناس أن يقيّموا كلمات باعتبار ما يمكن أن يكون؛ بل قيموها كما ترونها، لكن في نفس الوقت سأقول أن كلمات في صورتها الحالية هي [على ما أرجو] فصل في قصة أطول.
____________

ويبدأ بعض من المصريين في مهاجمة كل طموح في بلد أفضل لهم، ويظنون أن هذه هي الواقعية. وما تزال ترى العبارات المتكررة: "انت في مصر! احنا بلد .........! مش شايف الزبالة في الشوارع؟ مش شايف البلطجية؟".
____________

هل رأيت أبداً مبنى قد قارب أن يكتمل بناؤه الأساسي، لكن لم يبدأ "تشطيبه"؟ ستجد المبنى عبارة عن صورة من الرمال والطوب الأحمر والتراب والأسمنت؛ لكن هناك من يستطيع أن ينظر لنفس المبنى ويراه جميلاً رحباً.

أو بشيء أقرب لفكر المبرمج: تخيل فريقاً موهوباً قد كتب engine خاص بلعبة مليء بالإمكانيات المتقدمة، لكنه لم يكمل بعد صناعة الـmodels الخاصة بالشخصيات والمستويات. ستبدو اللعبة رديئة لمن  لا يعرف التفاصيل.

بدلاً من السخرية من هذا البناء نصف المكتمل فكر: كيف نكمله؟ كيف نريده أن يبدو في صورته النهائية؟