يتيح Common Lisp للمبرمج أن يكتب «تعليقات» يتجاهلها الحاسوب.
تبدأ التعليقات أحادية السطر بفاصلة منقوطة واحدة أو أكثر (;)، وقد ترى أحيانًا ما يلي:
(code...) ; => value
حيث يُستخدم التعليق هنا لبيان القيمة التي يُرجعها Common Lisp بعد تنفيذ الكود في ذلك السطر.
من الأسلوب المألوف أن تستخدم فاصلة منقوطة واحدة لتعليق قصير في نهاية السطر، واثنتين لتعليق أطول فوق قسم من الكود، وثلاثًا لتعليق طويل يصف شيئًا مثل دالة، وأربعًا لتعليق مثل ترويسة في أعلى ملف المصدر.
كل كائنات Common Lisp إما «ذرات» (قيم مفردة غير قابلة للتجزئة) وإما «أزواج cons» (تُبنى بالدالة البنائية cons).
يتكوّن زوج cons من جزأين: العنصر الأول وبقية العناصر.
ولأسباب تاريخية يُسمّى هذان الجزآن car وcdr.
وعندما تُقيَّم هذه الأزواج ككود، يمثّل العنصر الأول (car) الدالة التي تُستدعى، بينما تمثّل بقية العناصر (cdr) الوسائط التي تُمرَّر إلى تلك الدالة:
(<function> <arg1> <arg2> ... <argN>)
; ^ car ^ | ^ cdr ^
كل كود Common Lisp مكوّن من تعبيرات S (S-Expressions، التعبيرات الرمزية). وتُختصر تسميتها إلى sexprs. وكل sexpr إما ذرة وإما زوج cons. وعند تقييم تعبيرات S، فإنها تُرجع تلقائيًا قيمةً ما تحلّ محلّ التعبير. وعند كتابة دوالك الخاصة (باستخدام defun)، تُرجع تلقائيًا القيمة الأخيرة داخل جسم defun:
;; Defining a new function
(defun gimme-foo () 'foo)
;; Calling the function as an S-Expression
(gimme-foo) ; => FOO
الرموز في Common Lisp قيم خاصة يمكنها أن تشير إلى قيم أخرى، أو إلى نفسها في حالة الكلمات المفتاحية. وعندما يقيّم Lisp الرموز، تُستبدل بالقيم التي تشير إليها:
foo ; => <whatever-foo-points-to>
:foo ; => :FOO
لاحظ أن الكلمات المفتاحية تُكتب بنقطتين (:) في البداية.
الاقتباس، أي إضافة ' قبل تعبير S، يخبر Lisp بألّا يقيّم ذلك التعبير.
باقتباس 'foo في مثال defun، منعنا Lisp من أن يحاول البحث عن ما يُفترض أن يشير إليه FOO (وأن يفشل في العثور عليه)، بحيث يُرجع التعبير بدلًا من ذلك القيمة FOO نفسها.
وإذا لم يكن FOO معرَّفًا في أي مكان في برنامجنا:
foo ; => <ERROR! Lisp doesn't know what foo points to!>
'foo ; => FOO
في الوقت الحالي، يمكنك اعتبار هذا مجرد وسيلة لإرجاع الرموز من دالة، لكننا سنعود إلى الاقتباس ونستكشف آثاره أكثر في تمارين المفاهيم القادمة.
أنت! نعم أنت، يا مبرمج ليسب الشجاع! ليني، الكائن الفضائي من عالم ليسب، يحتاج إلى مساعدتك! يريد ليني أن يخرج ويلعب مع بقية الكائنات الفضائية من عالم ليسب، لكن والديه أخبراه أنه لن يذهب إلى أي مكان حتى تُرتَّب غرفته.
المشكلة أن ليني بالكاد يرى الأرضية! لا يستطيع ليني التمييز بين ذراته وأزواجه، ولا بين رموزه وكلماته المفتاحية، ولا بين car وcdr!
هل يمكنك مساعدة ليني في ترتيب هذه الفوضى؟ لا تنسَ أقواسك الهلالية، فستحتاج إليها!
قبل أن يبدأ ليني، يحتاج إلى مراجعة سريعة لما تبدو عليه الرموز والكلمات المفتاحية، فقد مضى وقت طويل منذ آخر مرة رتّب فيها غرفته... ساعد ليني بتعريف دالتين: lennys-favorite-food التي تُقيَّم إلى رمز ما، وlennys-secret-keyword التي تُقيَّم إلى كلمة مفتاحية ما. على سبيل المثال:
(lennys-favorite-food) ; => LASAGNA
(lennys-secret-keyword) ; => :ALIENS-ARE-REAL
لاحظ أنه يمكنك إرجاع أي رمز أو كلمة مفتاحية تريدها (إن لم تكن من محبي اللازانيا أو لم تكن مؤمنًا بوجود الكائنات الفضائية).
بعد أن يكون ليني قد أخذ فكرة عن الرموز والكلمات المفتاحية، حان وقت الترتيب! لفرز كل التعبيرات الرمزية المتناثرة في غرفته، يحتاج ليني إلى من يساعده في تحديد ما هو زوج وما هو ذرّة. يمكنك المساعدة بتنفيذ دالتين، is-an-atom-p وis-a-cons-p:
(is-an-atom-p 'one-thing) ; => T
(is-an-atom-p '(two things)) ; => NIL
(is-a-cons-p 'one-thing) ; => NIL
(is-a-cons-p '(two things)) ; => T
في هذا القسم، هناك عدد من دوال ليسب المدمجة التي قد تجدها مفيدة. إضافة إلى ذلك، يمكنك في الوقت الحالي ببساطة اعتبار T قيمة صحيحة وNIL قيمة خطأ.
أخيرًا، أزواج ليني ضخمة أكثر من أن تُرتَّب بشكل أنيق، لذا يحتاج إلى تقسيمها إلى أجزاء أصغر. هل يمكنك المساعدة بتعريف دالتين أخريين لتفكيك أزواجه (first-thing وrest-of-it)؟
(first-thing '(first second third)) ; => FIRST
(rest-of-it '(first second third)) ; => (SECOND THIRD)
مجددًا، قد تفيدك هنا بعض دوال Common Lisp المدمجة.
سجّل في Exercism لتتعلّم وتتقن Common Lisp عبر 27 مفهومًا92 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.