منذ بعض الوقت (حوالي ثلاث سنوات) قررت قراءة كتاب عن Lisp. بدون أي غرض محدد ، فقط من أجل التطور العام والقدرة على صدمة المحاورين بدخيل (بمجرد أن يبدو الأمر ، فقد نجح).
ولكن بعد الفحص الدقيق ، تبين أن Lisp قوية حقًا ومرنة ، ومن الغريب أنها مفيدة في الحياة اليومية. تم ترحيل جميع مهام الأتمتة البسيطة بسرعة إلى النصوص البرمجية في Lisp ، وكانت هناك أيضًا فرص لأتمتة النصوص الأكثر تعقيدًا.
وتجدر الإشارة هنا إلى أنه من خلال "القدرة على الأتمتة" ، أعني الحالة التي يكون فيها الوقت الإجمالي لكتابة البرنامج وتصحيحه أقل من الوقت المنقضي في حل نفس المهمة يدويًا.
كتب بول جراهام أكثر من مقال واحد وحتى كتابًا عن فوائد ليسب. في وقت كتابة هذه السطور ، كان Lisp في المرتبة 33 في تصنيف TOIBE (ثلاث مرات مات من دلفي الميت). السؤال الذي يطرح نفسه: لماذا اللغة صغيرة جدا إذا كانت مريحة جدا؟ أعطى حوالي عامين من الاستخدام بعض التلميحات للأسباب.
المساوئ
1. هياكل البيانات المشتركةمفهوم يسمح لك بتحسين البرامج الوظيفية ، ولكنه محفوف بالأخطاء الدقيقة في الأمر. تتطلب إمكانية التلف العرضي لبنية بيانات غريبة عندما يتم تعديل متغير ليس له اتصال مرئي بالهيكل من المبرمج أن يراقب باستمرار ما يحدث خلف الكواليس وأن يعرف التنفيذ الداخلي لكل وظيفة مستخدمة (النظام والمستخدم). الشيء الأكثر إثارة للدهشة هو القدرة على إلحاق الضرر بجسم الوظيفة عن طريق تعديل قيمتها المرتجعة.
2. عدم وجود التغليفعلى الرغم من وجود مفهوم الحزمة ، إلا أنها لا علاقة لها
بالحزمة في Ada أو
الوحدة في دلفي. يمكن لأي رمز إضافة أي شيء إلى أي حزمة (باستثناء حزم النظام). يمكن لأي رمز استخراج أي شيء من أي حزمة باستخدام عامل التشغيل
:: .
3. الاختصارات العشوائيةما الفرق بين MAPCAN و MAPCON؟ لماذا في SETQ ، الحرف الأخير Q؟ بالنظر إلى عمر اللغة ، يمكنك فهم أسباب هذه الحالة ، لكني أريد أن تكون اللغة أنظف قليلاً.
4. multithreadingيرتبط هذا العيب بشكل غير مباشر بـ Lisp ويتعلق بشكل أساسي بالتنفيذ الذي أستخدمه - SteelBank Common Lisp. لا يدعم Common Lisp multithreading. فشلت محاولة استخدام التطبيق المقدم بواسطة SBCL.
من المؤسف رفض هذه الأداة المريحة ، لكن عدم الرضا يتراكم تدريجياً.
ابحث عن حل
أولاً ، يمكنك الانتقال إلى ويكيبيديا على صفحة Lisp. افحص قسم "اللهجات". اقرأ مقدمة موجزة لكل منها. وندرك أن طعم ولون جميع العلامات مختلفة.
إذا كنت تريد القيام بشيء ما ، فعليك القيام بذلك بنفسك
- جان بابتيست إيمانويل سورج
دعونا نحاول إنشاء Lisp الصحيح الخاص بنا عن طريق إضافة القليل من Ada ، والكثير من Delphi وقطرة من Oberon إليها. نسمي الخليط الناتج فوكس.
المفاهيم الأساسية
1. لا مؤشراتفي مكافحة PROBLEM-1 ، يجب تنفيذ جميع العمليات عن طريق نسخ القيم. حسب نوع بنية البيانات في التعليمات البرمجية أو عند الطباعة ، يجب أن تكون جميع خصائصها واتصالاتها الخارجية والداخلية مرئية بالكامل.
2. إضافة وحداتكجزء من مكافحة المشكلة 2 ، نستورد
العبوة ،
مع بيانات من Ada
واستخدامها . في هذه العملية ، نتجاهل مخطط الاستيراد / التظليل شديد التعقيد لرموز Lisp.
(package - ( ) () ())
(with -)
(use -)
3. اختصارات أقلستظل الاختصارات الأكثر شيوعًا والأكثر شيوعًا ، ولكنها في الغالب الأكثر وضوحًا:
const ،
var . وظيفة الإخراج المنسقة - تتطلب FMT تقليلًا ، حيث توجد غالبًا داخل التعبيرات.
Elt - أخذ عنصر - تم تسريبه من Common Lisp وتجذره ، على الرغم من عدم الحاجة إلى تقليله.
4. معرّفات غير حساسة لحالة الأحرفأعتقد أن اللغة الصحيحة (ونظام الملفات) {$ HOLYWAR +} يجب أن تكون غير حساسة لحالة الأحرف {$ HOLYWAR-} حتى لا تضغط على أدمغتها مرة أخرى.
5. سهولة الاستخدام مع تخطيط لوحة المفاتيح الروسيةيتجنب بناء الجملة Lisi بكل طريقة ممكنة استخدام الأحرف غير المتوفرة في أحد التخطيطات. لا توجد أقواس مربعة أو مجعدة. لا # ، ~ ، & ، <،> ، |. عند قراءة الحرف الرقمي ، تُعتبر الفاصلة والنقطة فواصل عشرية.
6. الأبجدية الموسعةأحد الأشياء اللطيفة في SBCL كان UTF-8 في التعليمات البرمجية. القدرة على إعلان الثوابت BEAR و VODKA و BALALAYKA يبسط إلى حد كبير كتابة رمز التطبيق. إن القدرة على إدراج Ω و Ψ و Σ تجعل الصيغ في الكود أكثر وضوحًا. على الرغم من أنه من الناحية النظرية هناك إمكانية لاستخدام أي أحرف Unicode ، إلا أنه من الصعب ضمان صحة العمل معهم (بدلاً من الكسل بدلاً من الصعب). نحن نقتصر على السيريلية واللاتينية واليونانية.
7. الحرف العدديةهذا هو ملحق اللغة الأكثر فائدة بالنسبة لي.
10_000
يبدو لي الخيار الأخير الأكثر جمالية ، لكنه الأكثر شعبية.
8. دوراتالدورات في Lisp غير قياسية وفوضوية جدًا. تبسيط إلى الحد الأدنى من مجموعة المعايير.
(for i 5
متغير الحلقة غير مرئي في الخارج.
(while )
9. جوتوليس عامل ضروري للغاية ، ولكن بدونه من الصعب إظهار إهمال قواعد البرمجة الهيكلية.
(block : (goto :))
10. توحيد النطاقهناك نوعان مختلفان من النطاقات في Lisp: TOPLEVEL والمحلي. وفقًا لذلك ، هناك طريقتان مختلفتان لإعلان المتغيرات.
(defvar A 1) (let ((a 1)) …)
في فوكس ، هناك طريقة واحدة فقط مستخدمة في المستوى الأعلى من البرنامج النصي وفي المناطق المحلية ، بما في ذلك الحزم.
(var A 1)
إذا كنت ترغب في تحديد النطاق ، استخدم عامل التشغيل
(block (var A 1) (set A 2) (fmt nil A))
يتم تضمين نص الحلقة في عبارة BLOCK الضمنية (مثل نص الوظيفة / الإجراء). يتم تدمير جميع المتغيرات المعلنة في الحلقة في نهاية التكرار.
11. أحرف ذات فتحة واحدةفي Lisp ، تعد الوظائف كائنات خاصة ويتم تخزينها في فتحة رمز خاصة. يمكن لحرف واحد تخزين متغير ووظيفة وقائمة خصائص في نفس الوقت. في الثعلب ، يرتبط كل حرف بمعنى واحد فقط.
12. ELT مريحةيبدو الوصول النموذجي إلى عنصر بنية معقدة في Lisp هكذا
(elt (slot-value (elt 1) '-2) 3)
يقوم Fox بتنفيذ عامل ELT موحد يوفر الوصول إلى عناصر من أي نوع مركب (القوائم ، السلاسل ، السجلات ، صفائف البايت ، جداول التجزئة).
(elt 1 \-2 3)
يمكن أيضًا الحصول على وظيفة متطابقة باستخدام ماكرو في Lisp
(defmacro field (object &rest f) " . (field *object* 0 :keyword symbol \"string\") . plist. ( ) . ." (if f (symbol-macrolet ((f0 (elt f 0))(rest (subseq f 1))) (cond ((numberp f0) `(field (elt ,object ,f0) ,@rest)) ((keywordp f0) `(field (getf ,object ,f0) ,@rest)) ((stringp f0) `(field (cdr (assoc ,f0 ,object :test 'equal)) ,@rest)) ((and (listp f0) (= 2 (length f0))) `(field (,(car f0) ,(cadr f0) ,object) ,@rest)) ((symbolp f0) `(field (,f0 ,object) ,@rest)) (t `(error " ")))) object))
13. تقييد طرق نقل المعلمة روتينهناك ما لا يقل عن خمسة أوضاع لنقل المعلمات في Lisp: إلزامي ،
واختياري ،
والراحة ،
والمفتاح ،
وكلها ومجموعتها التعسفية مسموح بها. في الواقع ، معظم التركيبات تعطي تأثيرات غريبة.
في Fox ، يُسمح باستخدام مجموعة من المعلمات المطلوبة وأحد الأوضاع التالية للاختيار من بينها
: مفتاح ،: اختياري ،: إشارة ،: راحة .
14. multithreadingلتبسيط كتابة البرامج متعددة الخيوط إلى أقصى حد ، تم اعتماد مفهوم فصل الذاكرة. عندما يتم إنتاج سلسلة رسائل ، يتم نسخ جميع المتغيرات المتاحة لمؤشر الترابط الجديد. يتم استبدال جميع مراجع هذه المتغيرات بمراجع للنسخ. لا يمكن نقل المعلومات بين التدفقات إلا من خلال الكائنات المحمية أو من خلال النتيجة التي يتم إرجاعها بواسطة التدفق عند الاكتمال.
تحتوي الأشياء المحمية دائمًا على أقسام حرجة لضمان العمليات الذرية. يتم تسجيل الدخول إلى الأقسام المهمة تلقائيًا - لا توجد عوامل تشغيل منفصلة لهذا في اللغة. تتضمن الكائنات المحمية: قائمة انتظار الرسائل ووحدة التحكم وواصفات الملف.
يمكن إنشاء سلاسل رسائل باستخدام وظيفة عرض متعددة الخيوط
(map-th (function (x) …) --)
يبدأ Map-th تلقائيًا عدد الخيوط يساوي عدد المعالجات في النظام (أو ضعف العدد إذا كان لديك Intel بداخله). في المكالمة العودية ، تعمل مكالمات الخريطة اللاحقة في مؤشر ترابط واحد.
بالإضافة إلى ذلك ، هناك وظيفة مؤشر ترابط مضمنة تنفذ إجراء / وظيفة في مؤشر ترابط منفصل.
15. النظافة الوظيفية في الكود الإلزاميالثعلب لديه وظائف للبرمجة الوظيفية والإجراءات الإجرائية. تخضع الإجراءات المعلنة باستخدام الكلمة الرئيسية للوظيفة لمتطلبات غياب الآثار الجانبية واستقلالية النتيجة عن العوامل الخارجية.
غير محقق
بعض الميزات المثيرة للاهتمام من Lisp ظلت غير محققة بسبب أولوية منخفضة.
1. الأساليب المعممةالقدرة على التحميل الزائد للوظائف مع defgeneric / defmethod.
2. الميراث3. المصحح المدمجعند حدوث استثناء ، يتحول مترجم Lisp إلى وضع التصحيح.
4. UFFIواجهة لتوصيل الوحدات المكتوبة بلغات أخرى.
5. BIGNUMدعم عمق البت التعسفي
مهملةتم اعتبار بعض ميزات Lisp واعتبارها عديمة الفائدة / ضارة.
1. مزيج من الأساليب الموجهةعندما يتم استدعاء طريقة لفئة ، يتم تنفيذ مجموعة من الطرق الأم ويمكن تغيير قواعد النسخة. يبدو السلوك النهائي للطريقة ضعيفًا.
2. إعادة التشغيليمكن لمعالج الاستثناءات إجراء تغييرات على حالة البرنامج وإرسال أمر إعادة التشغيل إلى التعليمات البرمجية التي أنشأت الاستثناء. يشبه تأثير التطبيق استخدام عامل GOTO للتبديل من وظيفة إلى أخرى.
3. الحساب الرومانييدعم Lisp نظام الأرقام ، الذي عفا عليه الزمن قبل وقت قصير من ظهوره.
استخدم
فيما يلي بعض الأمثلة البرمجية البسيطة.
(function crc8 (data :optional seed) (var result (if-nil seed 0)) (var s_data data) (for bit 8 (if (= (bit-and (bit-xor result s_data) $01) 0) (set result (shift result -1 8)) (else (set result (bit-xor result $18)) (set result (shift result -1 8)) (set result (bit-or result $80)))) (set s_data (shift s_data -1 8))) result)
التنفيذ
مترجم مكتوب في دلفي (FreePascal في وضع التوافق). تم بناؤه في Lazarus 1.6.2 وأعلى ، تحت Windows و Linux 32 و 64 بت. من التبعيات الخارجية ، يتطلب libmysql.dll. يحتوي على حوالي 15_000..20_000 خط. هناك حوالي 200 وظيفة مدمجة لأغراض مختلفة (بعضها زائد ثمانية مرات).
مخزنة هنايتم دعم الكتابة الديناميكية بطريقة تافهة - يتم تمثيل جميع أنواع البيانات المعالجة بواسطة ورثة نفس فئة TValue.
النوع الأكثر أهمية لـ Lisp - القائمة ، كما هو معتاد في دلفي ، فئة تحتوي على مجموعة ديناميكية من الكائنات من النوع TValue. بالنسبة لهذا النوع ، يتم تنفيذ آلية CopyOnWrite.
إدارة الذاكرة تلقائية على أساس العد المرجعي. بالنسبة للهياكل العودية ، يتم حساب جميع الروابط في الهيكل في وقت واحد. يبدأ تحرير الذاكرة فور خروج المتغيرات من النطاق. لا توجد آليات لتأخير بدء تشغيل جامع القمامة.
معالجة الاستثناءات تعمل على آلية مضمنة في دلفي. وبالتالي ، يمكن معالجة الأخطاء التي تحدث في التعليمات البرمجية للمترجم عن طريق التعليمات البرمجية القابلة للتنفيذ على فوكس.
يتم تنفيذ كل عامل أو وظيفة Lisi مضمنة كطريقة أو وظيفة في كود المترجم. يتم تنفيذ البرنامج النصي عن طريق استدعاء تطبيقات متكررة. يحتوي كود المترجم والنص البرمجي على مجموعة مكالمات مشتركة.
يتم تخزين متغيرات البرنامج النصي في الذاكرة الديناميكية بشكل مستقل. كل وظيفة معرفة من قبل المستخدم لها رصة خاصة بها لتخزين المراجع المتغيرة ، بغض النظر عن رصة المستوى الأعلى أو رصة الوظائف الأصلية.
من الصعوبات الخاصة تنفيذ عامل التخصيص (مجموعة) للعناصر الهيكلية. يؤدي حساب المؤشر للعنصر المطلوب مباشرة إلى خطر تعلق الروابط ، حيث لا يحظر بناء جملة Lisi تعديل الهيكل أثناء حساب العنصر المطلوب. كحل وسط ، يتم تطبيق "مؤشر السلسلة" - كائن يحتوي على مرجع لمتغير ومجموعة من المؤشرات الرقمية للإشارة إلى المسار داخل البنية. يكون هذا المؤشر عرضة أيضًا لمشكلة الروابط المتدلية ، ولكن في حالة حدوث فشل ، فإنه يولد رسالة خطأ ذات معنى.
أدوات التطوير
1. وحدة التحكم2. محرر نصمجهز بإبراز بناء الجملة والقدرة على تشغيل برنامج نصي قابل للتحرير في F9.

الخلاصة
في الحالة الحالية ، يحل المشروع المشاكل التي تم تصورها من أجلها ، ولا يتطلب المزيد من التطوير النشط. العديد من العيوب الموجودة لا تؤثر بشكل كبير على العمل.