مسیرها
/
Common Lisp
Common Lisp
/
تمرین‌ها
/
مرتب‌سازی جوراب‌ها و اس‌اکسپرها
مرتب‌سازی جوراب‌ها و اس‌اکسپرها

مرتب‌سازی جوراب‌ها و اس‌اکسپرها

تمرین یادگیری

مقدمه

توضیحات

Common Lisp به برنامه‌نویس اجازه می‌دهد «توضیحات» بنویسد که کامپیوتر آن‌ها را نادیده می‌گیرد. توضیحات تک‌خطی با یک یا چند نقطه‌ویرگول (;) شروع می‌شوند و گاهی ممکن است شکل زیر را ببینید:

(code...) ; => value

در این نمونه از توضیح استفاده شده است تا نشان دهد Common Lisp پس از اجرای کد آن خط چه مقداری را برمی‌گرداند.

مرسوم است که برای یک توضیح کوتاه در پایان خط از یک نقطه‌ویرگول، برای توضیحی بلندتر بالای بخشی از کد از دو نقطه‌ویرگول، برای توضیحی بلند که چیزی مانند یک تابع را توصیف می‌کند از سه نقطه‌ویرگول و برای توضیحی مانند سرصفحه در بالای یک فایل منبع از چهار نقطه‌ویرگول استفاده شود.

کنس

همه‌ی اشیاء Common Lisp یا «اتم» هستند (مقدارهایی یگانه و تجزیه‌ناپذیر) یا «کنس» (که با تابع سازنده‌ی cons ساخته می‌شوند). هر کنس از دو بخش تشکیل می‌شود: عنصر اول و بقیه‌ی عنصرها. به دلایل تاریخی، به این دو بخش car و cdr می‌گویند. وقتی این کنس‌ها به‌عنوان کد ارزیابی می‌شوند، عنصر اول (car) تابعی را نشان می‌دهد که فراخوانی می‌شود و بقیه‌ی عنصرها (cdr) آرگومان‌های آن تابع هستند:

(<function> <arg1> <arg2> ... <argN>)
; ^ car ^  |        ^ cdr ^

عبارات

تمام کد Common Lisp از S-Expressions (Symbolic Expressions) تشکیل شده است. به اختصار به آن‌ها «sexpr» می‌گویند. هر sexpr یا یک اتم است یا یک کنس. وقتی S-Expressions ارزیابی می‌شوند، به‌طور خودکار مقداری را برمی‌گردانند که جای آن عبارت را می‌گیرد. وقتی توابع خودتان را می‌نویسید (با استفاده از 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-Expression، به Lisp می‌گوید که آن عبارت را ارزیابی نکند. با نقل‌قول کردن 'foo در مثال defunمان، کاری کردیم که Lisp به‌جای تلاش برای یافتن آنچه FOO قرار بود به آن اشاره کند (و ناکامی در یافتنش)، خودِ مقدار FOO را برگرداند. اگر FOO هیچ‌جای برنامه تعریف نشده باشد:

foo  ; => <ERROR! Lisp doesn't know what foo points to!>
'foo ; => FOO

فعلاً می‌توانید این را صرفاً راهی برای برگرداندن نمادها از یک تابع در نظر بگیرید، اما در تمرین‌های مفهومی آینده دوباره به نقل‌قول برمی‌گردیم و پیامدهای آن را بیشتر بررسی می‌کنیم.

دستورالعمل‌ها

شما! بله، شما، ای لیسپ‌کار شجاع! Lenny، موجود فضایی لیسپ به کمکتان نیاز دارد! Lenny می‌خواهد برود و با بقیه‌ی موجودات فضایی لیسپ وقت بگذراند، اما پدر و مادرش به او گفته‌اند که تا اتاقش تمیز نشود، هیچ‌جا نمی‌رود.

مشکل این است که Lenny به‌سختی می‌تواند کف اتاق را ببیند! Lenny نمی‌تواند «اتم»ها را از «کنس»ها، «نماد»ها را از «کلیدواژه»ها، و carها را از cdrها تشخیص دهد!

می‌توانید به Lenny کمک کنید تا این بی‌نظمی را سامان دهد؟ پرانتزهایتان را فراموش نکنید، به آن‌ها نیاز پیدا می‌کنید!

1. یادآوری نمادها به Lenny

قبل از اینکه Lenny بتواند شروع کند، لازم است یادآوری‌ای داشته باشد از اینکه نمادها و کلیدواژه‌ها چه شکلی هستند. مدتی طولانی از آخرین باری که اتاقش را مرتب کرده می‌گذرد... با تعریف دو تابع به Lenny کمک کنید: lennys-favorite-food که به یک نماد ارزیابی می‌شود و lennys-secret-keyword که به یک کلیدواژه ارزیابی می‌شود. برای مثال:

(lennys-favorite-food) ; => LASAGNA
(lennys-secret-keyword) ; => :ALIENS-ARE-REAL

توجه کنید که می‌توانید هر نماد یا کلیدواژه‌ای را که دوست دارید برگردانید (اگر طرفدار لازانیا نیستید یا به موجودات فضایی اعتقاد ندارید).

2. کمک به Lenny برای تشخیص اتم از کنس

وقتی Lenny یادآوری نمادها و کلیدواژه‌ها را از سر گذراند، وقت تمیزکاری است! برای مرتب کردن همه‌ی S-Expressionهایی که در اتاقش پخش شده‌اند، Lenny به کمک نیاز دارد تا تشخیص دهد چه چیزی کنس است و چه چیزی اتم. می‌توانید با پیاده‌سازی دو تابع کمک کنید: 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 را «غلط» در نظر بگیرید.

3. کمک به Lenny برای تقسیم کنس‌هایش

در نهایت، کنس‌های Lenny آن‌قدر حجیم هستند که مرتب جمع نمی‌شوند، پس باید آن‌ها را به بخش‌های کوچک‌تر تقسیم کند. می‌توانید با تعریف دو تابع دیگر به تقسیم کنس‌هایش کمک کنید (first-thing و rest-of-it)؟

(first-thing '(first second third)) ; => FIRST
(rest-of-it  '(first second third)) ; => (SECOND THIRD)

باز هم، ممکن است برخی از توابع توکار Common Lisp اینجا به کارتان بیایند.

ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Common Lisp Exercism

آماده‌اید مرتب‌سازی جوراب‌ها و اس‌اکسپرها را شروع کنید؟

در Exercism ثبت‌نام کنید تا Common Lisp را همراه با 27 مفهوم92 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.