با توجه به اینکه نام زبانی که داریم استفاده میکنیم، یعنی Lisp، مخفف LIST Processing است، ممکن است فکر کنید این زبان امکاناتی برای کار با لیستهایی از عنصرها دارد، و حق با شماست!
هرچند Common Lisp ساختارهای دادهای جز لیست هم دارد، لیستها هنوز بسیار پرکاربردند.
لیست در Common Lisp دنبالهای از عنصرهاست. به آن cons هم میگویند (بیشتر به دلایل تاریخی).
خود عنصرها لازم نیست همنوع باشند.
برای مثال میتوانید لیستی داشته باشید شامل 1، two و "III".
کافی است لیستی نقلقولشده مثل '(1 two "III") را تایپ کنید؛ آنگاه لیستی ساخته و ارزیابی میشود (که به (1 two "III") ارزیابی میشود).
دو تابع اصلی هم برای ساختن لیست وجود دارد: list و cons.
list صفر یا چند آرگومان میگیرد و به لیستی که با آن مقدارها ساخته شده ارزیابی میشود:
(list 1 'two "III") ; => (1 two "III")
cons دو عنصر میگیرد و لیستی میسازد که عنصر اولش car آن (سرِ لیست) است و عنصر دومش cdr آن (بقیهی لیست):
(cons 1 2) ; => (1 . 2) ;; (a list without `nil` as its `cdr` is printed in this way)
(cons 1 nil) ; => (1)
(cons 1 (cons 2 nil)) ; => (1 2)
با توابع car و cdr میتوان به car و cdr یک لیست دسترسی پیدا کرد.
(first و rest هممعنی car و cdr هستند و دقیقاً به یک شکل کار میکنند.)
طول یک لیست را میتوان با length تعیین کرد.
طول یک لیست خالی صفر است.
میتوان با nth به عنصری دلخواه دسترسی پیدا کرد (توجه کنید که ایندکس لیستها از ۰ شروع میشود).
درخواست ایندکسی بزرگتر از طول لیست خطا نیست.
در عوض، به nil ارزیابی میشود:
(nth 23 '(short list)) ; => nil
چند متد کمکی هم برای دسترسی به عنصرهای اول لیست وجود دارد: first، second، third و همینطور تا tenth. جالب است، نه؟
دو لیست یا بیشتر را میتوان با append ترکیب کرد:
(append '(a b c) '(1 2 3)) ; => (A B C 1 2 3)
(append '(a b c) '()) ; => (A B C)
هر آرگومانی که به append داده میشود باید یک لیست باشد.
لزلی، بیگانهی Lisp، باید خرید کند. داشتن یک لیست خرید بسیار مهم است. باید عناصری را به آن اضافه کرد و عناصری را از آن حذف کرد.
البته قلم و کاغذ ساده برای یک بیگانهی Lisp کافی نیست. حتی «List» بیشتر کلمهی «Lisp» است! باید چند تابع نوشته شود تا به پیگیری خرید کمک کند.
آیا میتوانید به لزلی در پیگیری لیست خرید کمک کنید؟
اولین کار این است که لزلی باید یک لیست خالی ایجاد کند. تابعی به نام new-list برای این کار عالی است.
(new-list) ; => ()
اوه نه... لزلی از قبل چند مورد در ذهن دارد، بنابراین به تابعی نیاز دارد که سه عنصر بگیرد (خوشبختانه لزلی فقط لیستی از سه عنصر میسازد. نه بیشتر، نه کمتر!) و یک لیست خرید جدید با آن موارد ایجاد کند. تابعی به نام list-of-things بنویسید که سه عنصر میگیرد و لیستی از آنها برمیگرداند.
(list-of-things 'bread 'milk 'butter) ; => '(bread milk butter)
قبل از رفتن به فروشگاه، لزلی در انبار غذا را نگاه میکند تا ببیند چه موردی لازم دارد. با نوشتن تابع add-to-list به آنها کمک کنید که یک عنصر را به ابتدای لیست اضافه میکند.
(add-to-list 'butter '(bread)) ; => '(butter bread)
هنگام خرید، لزلی میخواهد بداند برای بعدی به دنبال چه موردی بگردد. آنها همچنین دوست دارند در لیست جلوتر را ببینند تا عنصر دوم، سوم، یا حتی بیست و سومین (عدد شانسشان) را ببینند.
first-thing به اولین عنصر لیست ارزیابی میشودsecond-thing به عنصر دوم ارزیابی میشودthird-thing به عنصر سوم ارزیابی میشودtwenty-third-thing به عنصر بیست و سوم ارزیابی میشود(first-thing '(bread butter milk)) ; => 'bread
(second-thing '(bread butter milk)) ; => 'butter
(third-thing '(bread butter milk)) ; => 'milk
لزلی میخواهد اولین عنصر لیست را پیدا کند و آن را از قفسه بردارد. با نوشتن تابع remove-first-item به آنها کمک کنید. این تابع به لیستی ارزیابی میشود که شامل همهی موارد به جز اولین عنصر لیست ورودی است.
(remove-first-item '(bread butter milk)) ; => '(butter milk)
لزلی متوجه شد که به طور تصادفی دو لیست خرید ساخته است، نه یکی! تابعی به نام list-append بنویسید که لیستی را برمیگرداند که شامل عناصر لیست اول و سپس عناصر لیست دوم است.
(list-append '(bread salt) '(butter milk)) ; => '(bread salt butter milk)
لزلی نگران شده است که این سفر خرید کمی طول بکشد. فقط چند مورد در این لیست وجود دارد؟ تابعی به نام just-how-long بنویسید تا به آنها بگوید لیستشان چقدر طولانی است.
(just-how-long '(bread milk butter salt)) ; => 4
در Exercism ثبتنام کنید تا Common Lisp را همراه با 27 مفهوم92 تمرین و مربیگری انسانی واقعی یاد بگیرید و در آن استاد شوید، همهی اینها رایگان.