لیسپ معمولی

انگلیسی
لیسپ معمولی، که معمولا به صورت CL مخفف می‌شود، یک نوع از لیسپ است که به وسیله ANSI *۳۰۲۶۶–۱۹۹۴ استاندارد شده و برای استاندارد کردن نسخه‌های منشعب شده لیسپ که بخش‌هایی از آن را دارا هستند، گسترش یافته‌است. CL در واقع یک پیاده‌سازی نیست بلکه یک مشخصه زبانی است که پیاده‌سازی‌های لیسپ با آن مطابقت دارد.
لیسپ معمولی یک زبان برنامه‌نویسی همه منظوره‌است، در مقایسه با نسخه‌های لیسپ مانند Lisp Emacs و Auto Lisp که زبان‌های جامع جاسازی شده در تولیدات ویژه هستند. برخلاف بسیاری از لیسپهای اولیه، لیسپ معمولی مانند Scheme از حوزه لغوی برای متغیرها استفاده می‌کند.
لیسپ معمولی یک زبان برنامه‌نویسی چند نمونه‌ای است که:
مدل‌های برنامه‌نویسی مانند برنامه‌نویسی برنامه‌نویسی شیءگرا، برنامه‌نویسی تابعی و برنامه‌نویسی امری را پشتیبانی می‌کند.
به صورت پویا نوع دار شده‌است، اما با اعلان‌های نوع اختیاری که می‌تواند امنیت یا بازدهی را بهبود بخشد.
قابل گسترش در بین خصیصه‌های استاندارد مانند ماکروها و ماکروهای خواننده‌است.
نحو
لیسپ معمولی یک است؛ که از عبارات نحوی برای دلالت بر کد و ساختمان داده استفاده می‌کند. فراخوانی‌های ماکرو و تابع به صورت لیستی با آوردن نام تابع در ابتدا نوشته شده‌است، مانند مثال زیر:
۲ و ۲ را جمع می‌کند و نتیجه ۴ می‌دهد:
(+ 2 2)
به متغیر "p" مقدار ۳٫۱۴۱۵ می‌دهد:
(setf *p* 3.1415)
تعریف یک تابع که مجذور یک عدد را حساب می‌کند:
(defun square (x)
(* x x))
اجرای تابع که عدد ۹ را برمی‌گرداند:
(square 3)
انواع داده
لیسپ معمولی انواع داده‌ای زیادی حتی بیشتر از بسیاری زبان‌ها دارد.
انواع اسکالر
انواع عدد شامل اعداد صحیح، کسری، ممیز شناور و اعداد مختلط می‌باشد. لیسپ معمولی از bignums برای نشان دادن مقدارهای عددی با دقت و اندازه دلخواه استفاده می‌کند. نوع کسری، کسرها را با دقت نشان می‌دهد، این ویژگی در بسیاری از زبان‌ها وجود ندارد. لیسپ معمولی به صورت اتوماتیک مقدارهای عددی را بین این داده‌ها به صورت مناسب وارد می‌کند.
نوع کاراکتر لیسپ معمولی به کاراکترهای ASCII محدود نمی‌شود- تعجب‌آور نیست وقتی لیسپ، ASCII را نیز شامل می‌شود. بعضی از پیاده‌سازی‌های مدرن به کاراکترهای یونی کد نیز اجازه استفاده می‌دهد.
نوع سمبل نیز در زبان‌های لیسپ رایج است، اما عموما خارج از آن‌ها شناخته شده نیست. یک سمبل یک شی داده‌ای نامدار واحد است. سمبل‌ها در لیسپ شبیه شناسه‌ها در زبان‌های دیگر هستند، که به عنوان متغیرها برای نگهداری ارزش‌ها استفاده می‌شوند. اگرچه، آن‌ها بسیار عمومی‌تر هستند و می‌توانند برای خودشان هم استفاده شوند. معمولا وقتی یک سمبل ارزیابی می‌شود، مقدارش به عنوان یک متغیر برگردانده می‌شود. استثناهایی نیز وجود دارد: سمبل‌های کلمات کلیدی مثل: foo با خودشان ارزیابی می‌شوند و مقدارهای بولی در لیسپ معمولی به وسیله سمبل‌های رزرو شده T و NIL نشان داده می‌شوند.
ساختمان‌های داده
انواع ترتیبی در لیسپ معمولی شامل لیست‌ها، بردارها، بردارهای بیتی و رشته‌ها می‌باشد. مانند لیسپهای دیگر، لیست‌ها در لیسپ معمولی از consها ساختمان داده با دو بخش است که car وcdr نامیده می‌شود. یک لیست یک زنجیره پیوندی از cons هاست؛ که car مربوط به cons به عضوی از یک لیست ارجاع می‌کند (احتمالا لیست دیگر). هر cdr مربوط به cons، به cons بعدی اشاره می‌کند به جز آخرین cons که مقدارش به nil اشاره می‌کند.consها به راحتی برای پیاده‌سازی درخت‌ها و دیگر ساختمان‌های داده پیچیده استفاده می‌شوند: اگر چه توصیه می‌شود که از نمونه‌های کلاس یا ساختار به جای آن استفاده شود.
لیسپ معمولی آرایه‌های چند بعدی را پشتیبانی می‌کند، و می‌تواند به صورت پویا در صورت نیاز آرایه‌ها را دوباره سایز دهی بکند. آرایه‌های چند بعدی می‌تواند برای ریاضیات ماتریسی به کار روند. بردار یک آرایه یک بعدی است. آرایه‌ها می‌توانند هر نوع داده‌ای را به عنوان اعضاء داشته باشند (حتی انواع ترکیبی در همان آرایه) یا می‌توانند برای شامل شدن نوع خاصی از اعضاء، تخصصی شوند مثلا دربرداری از اعداد صحیح. بسیاری از پیاده‌سازی‌ها می‌توانند توابع آرایه‌ای را وقتی که آرایه‌ها در نوع‌های تخصصی شده به کار می‌روند، بهینه کند. دو نوع آرایه‌ای تخصصی شده، استاندارد هستند: رشته برداری از کاراکترهاست در حالی که بردار بیتی، برداری از بیت‌ها است.
جداول Hash پیوستگی بین شی‌های داده‌ای را ذخیره می‌کند. هر شی ممکن است به عنوان کلید یا مقدار استفاده شود. جداول Hash نیز مانند آرایه‌ها می‌توانند به صورت اتوماتیک در مواقع نیاز دوباره سایزدهی شوند.
بسته‌ها مجموعه‌ای از سمبل‌ها هستند که به‌طور عمده برای جداسازی بخش‌های یک برنامه به فضاهای نامی به کار می‌روند. یک بسته بعضی از سمبل‌ها را خارج کرده و به عنوان بخشی از یک واسط عمومی مشخص می‌کند.
ساختارها، شبیه structها در Cو رکوردها در پاسکال، ساختمان‌های داده‌ای پیچیده دلخواه با هر عدد و نوعی از زمینه‌ها را نشان می‌دهند.
توابع
در لیسپ معمولی، نوع داده یک نوع دادهای است. به عنوان نمونه، این امکان وجود دارد که تابعی نوشته شود که توابع دیگر را به عنوان آرگومان می‌پذیرد و همین‌طور به عنوان خروجی برمی‌گرداند. این خواصیت این امکان را فراهم می‌کند که عملیات بسیار عمومی را به توان تشریح کرد.
کتابخانه لیسپ معمولی شدیدا به چنین توابع مرتبه بالاتری تکیه می‌کند. مثلا تابع sort عملگر مقایسه را به عنوان آرگومان می‌پذیرد؛ بنابراین نه تنها می‌تواند هر نوع داده‌ای را مرتب کند بلکه ساختمان داده را نیز مطابق با یک کلید مرتب می‌کند.
لیست را با استفاده از اپراتور
)
لیست را مطابق با عنصر اول از هر زیر لیست مرتب می‌کند و (۳b) (4 c) (9 a) را برمی‌گرداند:
(sort (list (9 A) (3 B) (4 C)) #<:key #first)
مدل عرض یابی برای توابع بسیار ساده‌است. وقتی که عرضیاب‌کننده با فرم (F A۱ A۲. . .) مواجه می‌شود باید فرض کند که سمبولی که F نامیده می‌شود یکی از گزینه‌های زیر است:
یک عملگر ویژه (به آسانی در یک لیست ثابت چک می‌شود).
یک عملگر ماکرو (باید قبلا تعریف شده باشد)
نام یک تابع (پیش فرض، که ممکن است یک سمبل یا یک زیر شکل باشد که با سمبل lambda شروع می‌شود.
اگر F نام یک تابع باشد، آنگاه آرگومان‌های A1, A۲، … An با ترتیب چپ به راست عرض یابی می‌شوند و آن مقادیر را به عنوان پارامتر می‌گیرد.
فضای نامی تابع
در اینجا یک تفاوت اساسی بین لیسپ معمولی و Scheme وجود دارد. در CL، نام تابع در یک فضای نامی جستجو می‌شود که از فضای نامی مربوط به متغیرها جدا می‌باشد و فضای نامی تابع نامیده می‌شود. عملگرهایی که نام‌ها را در فضای عمومی تعریف می‌کنند شامل defun, flet و labels هستند.
برای فرستادن تابع با اسم به عنوان یک آرگومان به تابع دیگر، بعد از عملگر ویژه تابع که عموما با علامت # خلاصه می‌شود استفاده کرد. مثال sort اول به تابعی اشاره می‌کند که نام دارد.
مدل ارزیابی Scheme ساده‌تر است تنها یک فضای نامی وجود دارد و همه مکان‌ها در فرم ارزیابی می‌شوند (با هر ترتیب) — نه فقط آرگومان‌ها. چ
گاهی برای برنامه نویسان با تجربه، کدی که در یک نسخه نوشته شده در نسخه‌های دیگر گیج‌کننده‌است. به‌طور نمونه، بسیاری از برنامه نویسان CL ممکن است از نام‌های متغیر توصیفی مثل لیست یا رشته استفاده کنند که در Scheme غیرمجاز است و آن‌ها با نام‌های توابع برخورد پیدا می‌کنند. اگر چه فضای نامی مجزا برای توابع یک حسن است، یک منبع مجادله در خانواده لیسپ می‌باشد؛ که معمولا به عنوان Lisp-۱ و Lisp-۲ مورد ارجاع قرار می‌گیرد. این اسامی در مقاله‌ای در سال ۱۹۸۸ از ریچارد پ. گابریل ایجاد شد که به‌طور جامع ای دو روش را مقایسه می‌کند.
سرانجام، در حالی که تعریف یک تابع (شکل befun) یک لیست است، توابع عموما به صورت داخلی به صورت لیست نشان داده نمی‌شوند.
انواع دیگر
انواع دیگر داده‌ای در لیسپ معمولی شامل موارد زیر است:
نام مسیر که نماینده فایل‌ها و شاخه‌ها در سیستم فایلی است. چون از لحاظ قدمت Lisp جدای از Unix بود، ویژگی نام مسیر لیسپ معمولی عمومی‌تر از قراردادهای نام فایل بیشتر سیستم‌عامل‌ها است و این ویژگی دسترسی به فیل‌ها را در برنامه‌های Lisp به‌طور گسترده‌ای قابل انتقال در سیستم‌های گوناگون می‌کند.
جریان‌های ورودی و خروجی نشان دهنده تخلیه و تغذیه داده‌های متنی یا باینری هستند مانند فایل‌های باز یا نمایی.
لیسپ معمولی دارای بلوک ساختمانی تولیدکننده اعداد تصادفی کاذب هستند. اشیاء تصادفی نماینده منابع قابل استفاده مجدد اعداد تصادفی کاذب هستند و به کاربر اجازه می‌دهند که PRNG را راه اندازی کند یا منجر به اجرای مجدد یک توالی از آن شود.
شرایط یک نوع ویژه‌است که برای نشان دادن خطاها، استثناها و دیگر وقایع که یک برنامه ممکن است به آن‌ها پاسخ دهد استفاده می‌شوند.
لیسپ معمولی در ضمن شامل جعبه ابزاری برای برنامه‌نویسی شی گرا به نام سیستم شی‌ای لیسپ معمولی یا CLOS است.
ماکروها
یک ماکرو در Lisp به‌طور سطحی شبیه یک تابع در حال استفادده‌است. اگرچه، نشان دهنده عبارتی است که ارزیابی شده‌است، نماینده یک تغییر شکل کد اصلی برنامه نیز می‌باشد. ماکروها به برنامه نویسان Lisp امکان ایجاد فرم‌های نحوی جدید در زبان را می‌دهد. به عنوان نمونه، این ماکرو شکل حلقه until را ایجاد می‌کند، که ممکن است در زبان‌هایی مثل Perl آشنا به نظر می‌رسد:
(defmacro until (test -body body)
`(do ()
(,test)
,@body))
;; example
(until (= (random 10) 0)
(write-line "Hello"))
همه ماکروها باید قبل از این که کد اصلی شامل آن‌ها ارزیابی یا کامپایل شود، گسترش یابند. ماکروها می‌توانند به عنوان توابعی که درخت‌های نحوی انتزاعی را می‌پذیرند و برمی‌گردانند ملاحظه شوند. این توابع قبل از اینکه کامپایلر کد اصلی نهایی را تولید کند، احضار می‌شوند. ماکروها در لیسپ معمولی معمولی نوشته شده‌اند، و هر عملگر لیسپ معمولی را می‌توانند استفاده کنند. نکته‌ای که در بالا ذکر شد توسط لیسپ معمولی برای ساده کردن مورد معمول از جایگزینی در قالب‌های یک کد، ایجاد شده‌است.
گرفتن متغیرها و سایه اندازی آن‌ها
ماکروهای لیسپ معمولی قادر به گرفتن متغیر هستند، موقعیتی که در آن‌ها سمبل‌ها در بدنه گسترش یافته ماکرو با سمبل‌های متن فراخوانی شده و منطبق می‌شوند. گرفتن متغیرها گاهی اوقات اثر مطلوبی دارد: به برنامه نویسان امکان ایجاد ماکروها را جایی که سمبل‌های مختلف، معنایی ویژه دارند، می‌دهد. اگرچه، می‌تواند خطاهای غیرمعمول و غیرقابل انتظاری را نیز ایجاد کند.
بعضی از سیستم‌های لیسپ مانند scheme، با استفاده از ماکروها از گرفتن متغیر جلوگیری می‌کنند — که ماکروهای تمیز نامیده می‌شوند. در لیسپ معمولی می‌توان بوسیله gensyms از گرفتن متغیرهای ناخواسته جلوگیری کرد – gensyms سمبل‌های واحد گارانتی شده‌ای هستند که می‌توانند در گسترش ماکروها بدون خطر گرفته شدن استفاده شوند.
مسئله دیگر سایه اندازی غیرعمدی عملگرهای استفاده شده در گسترش ماکروها است. مثلا، کد زیر را ملاحظه کنید که یک گرفتن متغیر غیرعمدی را نشان می‌دهد:
;; expansion of UNTIL makes liberal use of DO
(defmacro until (expression -body body)
`(do () (,expression) ,@body))
;; macrolet establishes lexical operator binding for DO
(macrolet ((do (…) … something else …))
(until (= (random 10) 0) (write-line "Hello")))
ماکرو UNTIL به شکلی گسترش می‌یابد که DO را فراخوانی کند، که به منظور ارجاع شکل ویژه پایه‌ای DO طرح‌ریزی شده‌است. اگر چه، در این متن، DO ممکن است معنای کاملا متفاوتی داشته باشد.
لیسپ معمولی مشکل سایه اندازی عملگر را با ممانعت از تعریف مجدد عملگرهای ساختمانی مثل DO در این مثال، اصلاح می‌کند. در ضمن، کاربران ممکن است کدهایشان را به بسته‌هایی تقسیم کنند. سمبل‌های ساختمانی در بسته لیسپ معمولی p یافت می‌شوند، که بوسیله سمبل‌ها در بسته کاربر سایه اندازی نمی‌شوند.
مقایسه با Lispهای دیگر
لیسپ معمولی بسیار با Scheme مقایسه می‌شود. چون آن‌ها دو نسخه معروف از Lispها هستند. Scheme از لحاظ تاریخی جدیدتر از LC است، و نه تنها از همان Lisp می‌آید بلکه به وسیله بعضی از همان مهندسین نیز ارائه شده‌است
Guy L. Steele با Gerald Jay Sussman, Scheme را طراحی کردند و کمیته استاندارد را برای لیسپ معمولی به کرسی نشاندند.
اغلب سیستم‌های Lisp که طراحی‌هایشان در لیسپ معمولی توزیع شده مثل Zetalisp و Franz Lisp تنها از متغیرهایی که به صورت پویا محدود شده‌اند استفاده کرده‌اند. Scheme متغیرهایی را به Lisp معرفی می‌کند که از لحاظ لغوی محدود شده‌اند و به صورت گسترده‌ای به عنوان یک ایده خوب شناخته شده و توسط CL اقتباس شده‌اند. CL متغیرهای محدود شده پویا را پشتیبانی می‌کند اما باید به‌طور صریح ذکر شود که آن‌ها دارای این مشخصه هستند.
لیسپ معمولی گاهی Lisp۲ نامیده می‌شود و Scheme, Lisp۱ که برمی گردد به استفاده CL از فضاهای نامی مجزا برای توابع و متغیرها، (در حقیقت، CL فضاهای نامی زیادی دارد مانند آنهایی که بری کلمات کلیدی loop و نام‌های بلوکی و قالب go به کار می‌روند).
به علاوه پیاده‌سازی‌ها قصد دارند به مجموعه‌های منشعبی از بسته‌های کتابخانه برسند که عملکردی را که در استاندارد پوشش داده نشده، تامین کنند. بعضی از این خصیصه‌ها به استاندارد اضافه شدند مانند CLOS و قرارداد LOOP؛ بقیه ویژه پیاده‌سازی باقی ماندند.
متاسفانه بسیاری از وسایل ارزشمند برای برنامه‌نویس مدرن مثل شبکه بندی TCP/IP همچنان استاندارد نشده باقی مانده‌اند. اگر چه، بسته‌های با کد باز برای پشتیبانی چنین خصیصه‌هایی به روش قابل انتقال ایجاد شده‌اند، یک نمونه قابل توجه آن پروژه مجمومه کد باز لیسپ معمولی است.
لیسپ معمولی برای پیاده‌سازی وسیله کامپایلیرهای افزایشی طراحی شده‌است. تعریف‌های استاندارد به منظور بهینه کردن کامپایل در مشخصات زبان پیشنهاد شده‌است. اغلب پیاده‌سازی‌های لیسپ معمولی، توابع را برای بومی کردن کد ماشین کامپایل می‌کنند. بقیه به کد بایت کامپایل می‌کنند، که سرعت را کاهش می‌دهد ولی قابلیت انتقال کد باینری را آسان می‌کند. این تصور غلط که Lisp یک زبان کاملا تفسیر شده‌است، بسیار متحمل است در نتیجه این حقیقت باشد که محیط‌های لیسپ معمولی یک اعلان با اثر متقابل را تامین می‌کند و اینکه توابع یکی یکی به یک ترتیب افزایشی کامپایل می‌شوند.
بعضی از پیاده‌سازی‌ها براساس Unix مثل CLISP، می‌توانند به عنوان مفسرهای متنی استفاده شوند؛ یعنی به وسیله سیستم به صورت شفاف به ترتیبی که مفسر Perl ویا Unix shell است، احضار شوند.
لیست پیاده‌سازی‌ها
پیاده‌سازی‌های قابل توزیع مجدد رایگان شامل موارد زیر است:
Allegro Common Lisp
برای ویندوز، FreeBsd، لینوکس، Apple Mac OS X، یونیکس و انواع مختلف آن. Allegro CL یک محیط توسعه یکپارچه (برای ویندوز و لینوکس) فراهم می‌کند و قابلیت‌های گسترده‌ای را برای تحویل درخواستهای نرم‌افزارها دارد.
Corman Common Lisp
پیاده‌سازی لیسپ معمولی برای ویندوز.
LispWorks
برای ویندوز، FreeBsd، لینوکس، Apple Mac OS X یونیکس و انواع مختلف آن.LispWorks یک محیط توسعه مجتمع (در دسترس برای همه سیستم‌عامل) و قابلیت‌های گسترده‌ای را فراهم می‌آورد.
Scieneer Common Lisp
که برای محاسبات با کارایی بالا - علمی طراحی شده‌است.
Armed Bear Common Lisp
نوعی پیاده‌سازی لیسپ معمولی است که بر روی ماشین مجازی جاوا اجرا می‌شود شامل یک کامپایلر افزون بر Java byte code، و به لیسپ اجازه دسترسی به کتابخانه‌های جاوا را می‌دهد. مسلح خرس کلر—هر چند از آن استفاده می‌شود Armed Bear Common Lisp در حال حاضر یک پروژه مستقل است
CMUCL
در اصل از دانشگاه کارنگی ملون که در حال حاضر به وسیله کاربران متعدد استفاده می‌شود. CMUCL از یک کامپایلر اصلی سریع مشهور استفاده می‌کند و شامل مفسر نمی‌باشد، به‌طور گسترده‌ای از پیاده‌سازی CL با کد منبع باز استفاده می‌کند، در Linux و BSD برای اینتل x۸۶ موجود هستند.
GNU CLISP
نوعی دیگر از لیسپ معمولی‌های متن باز می‌باشد
Steel Bank Common Lisp) SBCL)
یک شاخه از CMUCL است. SBCL با تاکید بیشتر روی قابلیت نگهداری، از CMUCL باز شناخته می‌شود. SBCL روی محیط CMUCL اجرا می‌شود بجز HP/UX؛ به علاوه روی لینوکس برای PowerPC, SPARC و MIPS و روی سیستم‌عامل Mac اجرا می‌شود.
GNU Common Lisp) GCL)
کامپایلر Lisp پروژه GNU. GCL هنوز کاملا آماده انجام ANSI نیست ولی پیاده‌سازیی از انتخاب برای پروژه‌های بزرگ مختلف شامل ابزارهای ریاضی Maxima و ACL۲ است.
لیسپ معمولی قابل جاسازی
که برای جاسازی شدن در کاربردهای C طراحی شده‌است.
OpenMCL
یک شاخه کد منبع باز از لیسپ معمولی مکینتاش. همانطوری‌که از اسم آن حاکی است، OpenMCL ویژه مکینتاش است و روی سیستم‌عامل Mac, Darwin و یونیکس برای PowerPC اجرا می‌شود.
Movitz
محیط Lisp را برای کامپیوترهای x۸۶ بدون تکیه بر سیستم‌عامل تکمیل می‌کند.
همچنین پیاده‌سازی‌های موجود غیر رایگانی از Franz, Xanalys, Digitool, Corman و Scieneer وجود دارد.
کاربردها
با وجود انتظارات بزرگ از کمیته استاندارد (CL گاهی به عنوان جایگزینی برای C معرفی می‌شود)، لیسپ معمولی یک زبان برنامه‌نویسی مناسب باقی ماند، که اغلب در دانشگاه یا محیط‌های کاربردی ویژه که در ارتباط با هوش مصنوعی است به کار می‌رود.
موارد کاربردی
لیسپ معمولی در بسیاری از برنامه‌های تجاری استفاده می‌شود، از جمله یاهو! سایر نمونه‌های قابل توجه عبارتند از:
بازی jak and daxter در کنسول پلس استیشن
OpenMusic یک شیء گرا محیط‌های برنامه‌نویسی و تصویری مبتنی بر لیسپ معمولی،
موتور جستجوی نرم‌افزار ITA که توسط سایت‌های گردشگری مانند orbitz و kayak.com و خطوط هواپیمایی مانندContinental Airlines, American Airlines و US Airlines استفاده می‌شود
همچنین برنامه‌های متن باز هم به با کمک لیسپ معمولی نوشته شده‌است که می‌توان به نمونه‌های زیر اشاره کرد:
Maxima، یک سیستم پیچیده جبر کامپیوتری
Stumpwm یک window manager بر اساس صفحه کلید تماما به وسیله لیسپ معمولی نوشته شده‌است
acl۲، کاربردی، یک ثابت‌کننده نظریه با تمام خصیصه‌ها برای زیر مجموعه‌ای از لیسپ معمولی است
Compo، زبانی که به ساختارهای موسیقی پیچیده اجازه توصیف به یک روش طبیعی را می‌دهد.
Lisa، سیستم تولید قانون برای ساختن نماینده‌های نرم‌افزاری «هوش