لیسپ

از ویکی‌پدیا، دانشنامهٔ آزاد
پرش به: ناوبری، جستجو


لیسپ یک زبان برنامه‌نویسی رایانه است که در سال ۱۹۵۸ به وسیلهٔ جان مک‌کارتی ابداع شده‌است. این زبان، مانند زبان برنامه‌نویسی پرولوگ، بیشتر برای برنامه‌نویسی هوش مصنوعی مورد استفاده قرار می‌گیرد. با توجه به اینکه زبان لیسپ از نحو ساده‌ای برخوردار است، تجزیه و پیاده‌سازی آن نسبتاً با سهولت انجام می‌شود.

ساختار کلی زبان لیسپ[ویرایش]

متن برنامه‌های لیسپ عموماً از نمادها و لیست‌هایی از نمادها تشکیل می‌شود و بدین خاطر است که این زبان لیسپ (مخفف پردازش لیست) نامیده شده‌است. یکی از ویژگی‌های جالب زبان لیسپ این است که خود برنامه‌های لیسپ نیز لیست هستند و بنا بر این، می‌توان با برنامه‌ها به عنوان داده‌ها رفتار کرد و یا داده‌ها را به عنوان برنامه ارزیابی نمود. لیسپ دارای گویش‌های مختلفی است که بعضی از آنها دارای قابلیت‌های شیءگرا نیز هستند. از این میان می‌توان به کامن لیسپ اشاره کرد. در ابتدا لیسپ به عنوان علامتگذاری و نمادسازی ریاضیات و برای برنامه‌های کامپیوتری ابداع شد. زبان لیسپ به سرعت مورد توجه برنامه نویسان از جمله برای تحقیقات علمی هوش مصنوعی قرار گرفت. لیسپ یکی از ابتدائی زبان‌های برنامه نویسی می‌باشد، و در علوم کامپیوتر بر بسیاری از تفکرات و ایده‌ها پیشگام بود. لیسپ شامل ساختمان دادهٔ درخت، مدریت نگهداری اتوماتیک، برنامه نویسی پویا، برنامه نویسی شی گرا و کامپایلر مستقل می‌باشد.

لیست یک مفهوم پایه‌ای در زبان لیسپ[ویرایش]

نام لیسپ از زبان پردازش لیست گرفته شده‌است. لینک لیست یکی از قسمت‌های اصلی ساختمان دادهٔ زبان لیسپ است و سورس کد لیسپ از لیست‌ها ساخته شده‌است و می‌تواند به عنوان ساختمان داده عمل کند. پیشرفت و توسعهٔ سیستم ماکرو به برنامه نویسان اجازه می‌دهد تا ترکیب‌های جدید ویا حتی حیطهٔ زبان‌های برنامه نویسی ویژه‌ای را ایجاد کرده و در زبان لیسپ تعبیه کنند. قابلیت تبادل کدها و داده‌ها به زبان لیسپ قابلیت تشخیص ترکیب‌ها را می‌دهد، همهٔ کدهای برنامه به صورت عبارت‌های نمادین یا لیست‌های پرانتز گذاری شده نوشته شده‌اند. یک تابع می‌تواند توسط خودش ویا توابع دیگر فراخوانی شود ویا طبق قواعد نحوی نوشتن یک لیست و استفاده از اول نام عملگرها و پیروی کردن از قواعد آرگومان‌ها ایجاد شود. به عنوان مثال تابع fدارای ۳ آرگومان می‌باشد و به صورت مقابل توانائی فراخوانی را دارد و مورد استفاده قرار می‌گیرد:

(f x y z)

تاریخچه زبان لیسپ[ویرایش]

زبان برنامه‎نویسی لیسپ توسط جان مک کارتی در سال ۱۹۵۸ در حالی که در مؤسسهٔ فناوری ماساچوست (MIT) بود ابداع شد. مک کارتی طرح خودش را در یک مقالهٔ مرتبط با انجمن ماشین آلات کامپیوتری در سال ۱۹۶۰ منتشر کرد. طرح وی در ابتدا به صورت «بخش اول:توابع بازگشتی از دید عبارت‌های نمادین و محاسبهٔ آنها توسط ماشین» ارائه شد و بخش دوم آن هیچگاه منتشر نشد. وی نشان داد که با یک تعداد ساده و کمی از عملگرها و علمتگذاری توابع می‌توان یک زبان تورینگ کامل برای الگوریتم‌ها ایجاد کرد. زبان پردازش اطلاعات اولین زبان هوش مصنوعی بود. از سال ۱۹۵۵ یا ۱۹۵۶ و پیش از آن ایده‌های بسیاری بر زبان لیسپ وارد شد از جمله پردازش لیست و توابع بازگشتی که در زبان لیسپ به کار برده شد. ثبت‌های اصلی مک کارتی به صورت عبارت‌های غیر نمادین که خواستار تفسیر کردن و برگرداندن به عبارت‌های نمادین بود. به عنوان مثال عبارت غیر نمادین car[consA,B معادل عبارت نمادین (car (cons A B)بود که در زبان لیسپ به کار گرفته شده بود. برنامه نویسان به سرعت عبارت نمادین را انتخاب و عبارت‌های غیر نمادین را ترک کردند. لیسپ برای اولین بار توسط استفان راسل روی یک کامپیوتر IBM 704 اجرا شد. راسل مقالهٔ مک کارتی را مطالعه کرد و دریافت که توابع لیسپ می‌توانند در کد ماشین اجرا شوند. این نتیجه از مطالعه و دریافت راسل نشان می‌دهد که مفسر لیسپ می‌توانست برای اجرای برنامه‌های لیسپ و ارزیابی صحیح عبارت لیسپ استفاده شود. دو زبان اسمبلی به عنوان دو عملیات اصلی و ابتدائی تجزیه و جدا کردن عناصر اصلی لیست برای IBM 704 شد. این دو زبان اسمبلی car (مضمون آدرس ثبات) و cdr (محتوای کاهش میزان ثبات‌ها) نسخهٔ لیسپ هنوز ازcar وcdr برای عملیاتی که اولین عنصر در یک لیست و باقی‌ماندهٔ لیست را برمی‌گرداند، استفاده می‌کند. اولین کامپایلر تکمیل شدهٔ لیسپ، در سال ۱۹۶۲توسط تام هارت و مایک لوین در MIT اجرا شد، این کامپالر معرفی شده مدل لیسپ با کامپایلر نحوی در هر کامپایل و ترجمهٔ توابع می‌تواند به طور رایگان در هم بیامیزد. زبان به کار گرفته شده در ثبت هارت و لوین نسبت به کدهای ابتدائی مک کارتی به شیوهٔ لیسپ مدرن و جدید نزدیک تر می‌باشد.

ویژگی‌های زبان لیسپ[ویرایش]

پیوستن به هوش مصنوعی[ویرایش]

بعد از شروع لیسپ، لیسپ به انجمن تحقیقاتی هوش مصنوعی پیوست، خصوصاً به سیستم‌های PDP، زبان لیسپ به عنوان پیاده‌ساز طرح کوچک زبان برنامه نویسی استفاده می‌شود که مبنایی برای سیستم معروف هوش مصنوعی SHRLU بود. در سال ۱۹۷۰ تحقیقات علمی هوش مصنوعی به شاخه‌های تجاری انشعاب پیدا کرد که کارایی سیستم لیسپ موجود در این زمینه یک روند رو به رشد شد. لیسپ یک سیستم مشکل برای اجرا، مهارت کامپایلر و سخت‌افزار ذخیره کننده را در سال ۱۹۷۰ دارا باشد. بازیابی عادی حافظه، توسط دانشجوی فارغالتحصیل MIT (دانیل ادوارد) گسترش داده شده، که برای اجرای لیسپ روی سیستم‌های محاساتی ساخته شده بود اما راندمان آن هنوز یک مشکل بود. برای رهبری ماشین لیسپ: سخت‌افزار اختصاصی برای اجرای محیط لیسپ و برنامه‌های آن استفاده می‌شود. پیشروی در هردو سخت‌افزار کامپیوتر و فناوری کامپایلر از ماشین‌های لیسپ از کار افتاده الهام گرفته شده‌است. طی شک کوشش بزرگ نسخه‌های بیشماری از زبان لیسپ را در یک زبان واحد متمرکز و متحد کردند (نسخه‌های برجسته و قابل ملاحظه‌ای شامل: اینترلیسپ، مک لیسپ، متالیسپ، و فرانزلیسپ) زبان‌های جدید (لیسپ عمومی و مشترک) در اصل یک زیر مجموعهٔ سازگاری از نسخه‌های تعویض شده بود. در سال ۱۹۹۴، ANSI یک لیسپ عمومی و مشترک استاندارد منتشر کرد. لیسپ عمومی و مشترک زبان برنامه نویسی فناوری اطلاعات ANSI X3.226-1994 در آن زمان فروشگاه‌های جهانی برای لیسپ خیلی کوچکتر از المان بود.

ترکیب و معنا شناسی[ویرایش]

لیسپ یک عبارت جهتدار است، برخلاف بیشتر زبان‌های دیگر، بین عبارت‌ها و جمله‌ها تمایز و فرقی وجود ندارد. همهٔ کدها و داده‌ها به عنوان عبارت‌ها نوشته شده‌اند – زمانی که یک عبارت ارزیابی می‌شود یک مقدار (یا یک لیستی از مقادیر) را می‌سازد، که آن هم در داخل عبارات دیگر جاسازی می‌شود. مقالهٔ ۱۹۵۸ مک کارتی دو نوع از ترکیب‌ها را معرفی کرد: عبارت نمادین Sexps هم نامیده می‌شود، که بازتابی از نمایش داخلی کدها و داده هاست و عبارت غیر نمادین هرگز مورد توجه قرار نگرفت و تقریباً همهٔ زبان‌ها امروزه از عبارات نمادین استفاده می‌کنند. استفاده از پرانتزگذاری‌ها تفاوت بسیار آشکار و مشهودی میان لیسپ و دیگر زبان‌های برنامه نویسی ایجاد کرده‌است. اسم مستعار LISP از Lost In Stupid Parenthese و یا Lost of Irritating Supper fluous parenthese گرفته شده‌است. هرچند ترکیب عبارت‌های نمادین مسئولی برای توان لیسپ است، این ترکیب به شدت با قاعده و منظم است. هرچند ترکیبات لیسپ به نمادگذاری قدیمی محدود نشده‌اند می‌تواند به سبک‌های دیگر توسعه پیدا کند. تکیه روی عبارت‌ها، قابلیت انعطاف‌پذیری زیادی به زبان می‌دهد، زیرا توابع لیسپ به صورت لیست نوشته شده‌اند، آنها دقیقاً مانند داده‌ها می‌توانند پردازش شوند، این قابلیت اجازه می‌دهد برنامه‌های لیسپ به سادگی و راحتی نوشته شوند و به نسبت برنامه‌های دیگر به راحتی اداره شوند. (برنامه نویسی غیر نمادین) بسیاری از نسخه‌های زبان لیسپ با عناصر جدا شده توسط فاصله‌های سفید و پرانتزگذاری شده‌ها نوشته می‌شود. برای مثال (1 2 f00) یک لیست است که عنصرهای آن سه اتم هستند (اتم: کوچکترین عضو لیست): این مقادیر ۱ و ۲ و F00 هستند. این مقادیر ضمناً دارای نوع داده‌ای خاصی هستند، مثلاً این لیست دارای دو عدد صحیح ۱ و ۲ و یک نوع دادهٔ ویژهٔ لیسپ که یک Symbol یا نماد نامیده می‌شود. همچنین یک لیست خالی () به عنوان یک اتم ویژهٔ صفر و یا پوچ معرفی شده‌است. موجودیت یک لیسپ از اتم و لیست تشکیل می‌شود. عبات‌ها به عنوان لیست نوشته شده‌اند، استفاده کردن از ثبت‌های پیشوندی، عناصر ابتدایی در لیست نامی از یک شکل تابع، عملگرها، ماکروها و یا اپراتورهای ویژه‌است. آرگومان‌ها باقی‌مانده‌هایی از لیست‌ها هستند، برای مثال تابع list آرگومان‌ها را به عنوان یک لیست بر می‌گرداند، بنابراین عبارت (list ‘۱ ‘۲ ‘foo) ارزیابی می‌شود و حاصل این ارزیابی لیست (۱٬۲،foo) می‌باشد. نیازی به ارزیابی کردن اعداد نیست چون ارزیابی عدد ۱ عدد ۱ می‌شود. آرگومان‌های مثال قبل از اعداد هستند یعنی آرگومان‌های ویژه که این آرگومان‌ها از ارزیابی کردن آرگومان‌ها جلوگیری می‌کنند چون مقادیر آن‌ها مشخص است. هر عبارتی که بیان می‌شود قبل از اینکه با عبارات دیگر پیوست داده شود به صورت بازگشتی ارزیابی می‌شود. (list(1 2 (list(3 4)))) در این مثال حاصل اررزیابی به صورت لیست (۱٬۲(۳٬۴)) می‌باشد، توجه کنید این لیست دارای ۳ آرگومان می‌باشد، لیست‌ها می‌توانند به صورت تو در تو باشند. اپراتورهای حسابگر به صورت همسان رفتار می‌کنند. حاصل عبارت (+۱ ۲ ۳ ۴) عدد ۱۰ می‌باشد. عبارت معادل عبارت بالا به صورت ۱+۲+۳+۴ می‌باشد که از نشانگذاری میان وندی استفاده شده‌است. اپراتورهای حسابگر در زبان لیسپ variadic(n-ary) که زبان لیسپ توانایی پذیرفتن هر تعداد آرگومان را داراست. عملگرهای ویژه ساختمان کنترل لیسپ را آماده می‌کنند. برای مثال، اپراتور ویژه if سه آرگومان می‌پذیرد، اگر اولین آرگومان صفر و یا خالی باشد دومین آرگومان ارزیابی می‌شود و در غیر این صورت هٔرگومان سوم بررسی می‌شود. بنابر این if(nill(list 1 2 “foo”)(list 3 4 “bar”) که تنها آرگومان (list 3 4 “bar”) بررسی می‌شود.

عبارت‌های لاندا (Lambda)[ویرایش]

دیگر عبارت‌های ویژه لاندا می‌باشد که برای وصل کردن متغیرها به مقادیرشان که درون یک عبارت ارزیابی می‌شوند استفاده می‌شود. این عملگر همچنین برای ایجاد کردن توابع هم استفاده می‌شود. آرگومان‌های درون لاندا یک لیستی از آرگومان‌ها هستند و عبارت ارزیابی توابع می‌باشند. مقادیر بازگشتی مقادیری از عبارت قبلی که ارزیابی شده‌اند هستند. عبارت (Lambda(arg)(+arg1)) زمانی که این تابع به کار برده می‌شود به صورت یک تابع ارزیابی می‌شود و وظیفهٔ این تابع معرفی کردن یک آرگومان و اتصال دادن آرگومان به arg و در نهایت برگرداندن یک عدد بزرگتر از آرگومان قبلی می‌باشد عبارت‌های لاندا خیلی متفاوت با نام تابع رفتار نمی‌کند بنابراین اگر در عبارت (Lambda(arg)(+arg1))5->۶ عدد ۵ را وارد کنیم خروجی آن ۶ می‌شود. اتم‌ها: در نسخهٔ اصلی لیسپ دو نوع دادهٔ ابتدایی وجود دارد: اتم‌ها و لیست‌ها یک لیست یک رشتهٔ منظم و محدودی از عناصر می‌باشد، که هر عنصر در درون خودش یکی از این اتم‌ها و یا لیست‌ها را دارد و یک اتم یک عدد یا یک نماد می‌باشد. در اصل یک نماد یک رقم منحصربه‌فرد می‌باشدو به عنوان یک رشتهٔ عددی در سورس کد نوشته شده و هر دو به عنوان یک نام متغیر و یک رقم داده‌ای در پردازش نمادین استفاده می‌شود برای مثال list(foo(BAR 1)2) شامل سه عنصر: Symbol foo و list(BAR 1) و عدد ۲ می‌باشد. تفاوت اصلی بین اتم‌ها و لیست‌ها این است که اتم‌ها تغییر ناپذیر و منحصربه‌فرد می‌باشند. دو اتم که دقیقاً به یک صورت و به یک روش در یک شی نوشته شده باشد در مکان متفاوتی در سورس کد ظاهر می‌شوند، هر لیست یک شی مجزا می‌باشد و به خاطر اینکه مستقل از دیگر لیست هاست و از دیگر لیست‌ها به وسیلهٔ مقایسهٔ عملگرها مشخص می‌شود.

Consها و لیست‌ها[ویرایش]

یک لیست لیسپ یک لینک لیست جداست، هر ذره از این لیست یک Cons نامیده می‌شود و از دو اشاره گر که Car و Cdr نامیده می‌شوند ترکیب شده‌است این دو اشاره گر به ترتیب معادل دو فیلد Data و Next در مقالهٔ لینک لیست می‌باشد.

Car -> Data
Cdr -> Next

بسیاری از ساختمان داده‌ها می‌توانند ترکیب‌هایی از خانه‌های Cons را داشت باشند، یکی از این ساختمان داده‌های ابتدایی لیست مخصوص نامیده می‌شود، یک لیست مخصوص هر دو نماد لیست خالی nill و یا خانه‌ها Cons را داراستکه در هر یک از این خانه‌ها هر اشاره گر Car به یک داده اشاره می‌کند (که ممکن است این اشاره گر Cons به یک لیست اشاره کند) و یک اشاره گر Cdr به یک لیست مخصوص دیگر اشاره می‌کند. اگر یک Cons داده به سر یک لینک لیست برده شود سپس اشاره گر Car آن به اولین عنصر از لیست و اشاره گر Cdr آن به انتهای یک لیست اشاره می‌کند به همین دلیل عملکرد Car و Cdr را به ترتیب first و rest هم نامیده می‌شود.

ارایهٔ لیست عبارت نمادین[ویرایش]

نمایش پرانتزگذلری عبارت نمادین ساختمان لینک لیست. چندین راه برای نمایش لیست یکسان به عنوان یک عبارت نمادین وجود دارد. یک خانه (Cons) می‌تواند به صورت نشان گذاری جفت نقطه گذاری شده نوشته شود به عنوان مثال (a.b) که در آن a یک Car و b یک Cdr است. یک لیست مخصوص بلند ممکن است به صورت یک نشان گذاری جفت نقطه گذاری شده نوشته شود.(a.(b.(c.(d.nill))))

طبق قرارداد کوتاه شدهٔ عبارت بالا به صورت (a b c d) در نمادسازی لیست می‌باشد یک لیست مخصوص ممکن است در یک ترکیبی از دو صورت (a b c.d) نوشته شود. برای سیستمی از سه Cons که آخرین Cdr آن d است.

دستورالعمل‌های پردازش لیست[ویرایش]

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

(list 1 2 ‘a 3);
Output: (1 2 a 3)
(list 1(2 3) 4);
Output: (1 (2 3) 4)

به این دلیل راهی که لیست‌ها ایجادمی شوند از جفت‌های Cons (Car,Cdr) پردازهٔ Cons می‌تواند برای اضافه کردن یک عنصر به جلوی یک لیست استفاده شود. توجه کنید که پردازهٔ Cons در هدایت و به کار بردن آرگومان‌های لیست نامتقارن است، بدین دلیل روش‌های لیست‌ها ایجاد می‌شوند.

(Cons 1(2 3));
Output: (1 2 3)
(Cons(1 2)(3 4))
Output: ((1 2) 3 4)

پردازهٔ Oppend دو یا چند لیست را با هم ادغام می‌کند و یک لیست واحد ایجاد می‌کند زیرا لیست لیسپ یک لینک لیست است و پیچیدگی زمانی الحاق کردن لیست‌ها از مرتبهٔ پیچیدگی زمانی O(n) می‌باشد. ساختار اشتراکی: لیست‌های لیسپ لینک لیست‌های ساده می‌توانند با یکی دیگر از لیست‌ها در ساختمان مشترک باشند به عبارت دیگر دو لیست می‌توانند دم یکسانی داشته باشندیا رشتهٔ پایانی از Consهای یکسانی داشته باشند مثلاً:

(setf foo (list 'a 'b 'c))
(setf bar (cons 'x (cdr foo)))

لیست foo و bar به ترتیب به صورت (a b c) و (X b c) هستند هرچند دم (b c) در هر دو لیست ساختار یکسانی دارند ولی مانند هم نیستند، خانه‌های Cons اشاره گر به b و c در محل حافظهٔ یکسانی برای هردو لیست قرار دارد. ساختار اشتراکی سریع تر از کپی کردن می‌تواند به صورت چشمگیری کارایی را بهبود بخشند. هرچند، این مهارت می‌تواند متقابلاً در راه‌های نامطلوب با عملکردهایی که تغییرات لیست‌های گذشته روی آرگومان‌های آن تاثیر بگذارد، اثر کند. تغییرات یک لیست از قبیل تغییر دادن C با یک goose روی دیگری نیز تاثیر می‌گذارد

setf (third foo) 'goose)

که این تغییر نتیجه را به صورت (a b goose) تغییر می‌دهد اما bar هم تغییر می‌کند (X b goose) که ممکن است یک نتیجهٔ غیر منتظره باشد. زبان‌های برنامه نویسی Lisp معمولاً از یک خط دستور محاوره‌ای استفاده می‌کنند، که می‌تواند با یک محیط پیچیدهٔ گسترش یافته ترکیب شود. کاربر اصطلاحات و دستورات را در خط دستور وارد کرده یا با رهبری IDE آنها را به سیستم Lisp می‌فرستد. Lisp دستورات را می‌خواند، آن‌ها را ارزیابی می‌کند و نتایج را چاپ می‌کند. به این دلیل است که خط دستور زبان Lisp به حلقهٔ Read-Eval-Print یا REPL معروف است. نمونهٔ ساده‌ای از عملیات REPL در زیر آمده‌است. این یک شرح ساده‌است که بسیاری از المان‌های Lispواقعی در آن نمی‌آید مانند ماکروها و کوئت‌ها. تابع read جملات متنی را به عنوان ورودی می‌پذیرد و آنها را به ساختار لیست تجزیه می‌کند. به عنوان مثال، وقتی شما رشتهٔ (+ ۱ ۲) را در اعلان تایپ می‌کنید، تابع read آن را به یک لیست پیوندی حاصل از ۳ المان ترجمه می‌کند: علامت +، عدد ۱ و عدد ۲. خیلی اتفاق می‌افتد که لیست قسمت موثری از یک کد Lisp باشد که قابل ارزیابی است. به همین دلیل است که یک قطار از لیست به یک تابع نام عملگر مع می‌دهد. تابع eval ساختار لیست را ارزیابی می‌کند و نوعی دیگر از ساختار را به عنوان نتیجه باز می‌گرداند. ارزیابی کردن لزوماً تفسیر کردن معنی نمی‌دهد؛ بعضی سیستم‌های Lisp هر عبارتی را به زبان ماشین تبدیل می‌کنند. خیلی ساده‌است؛ به هر حال؛ برای تعریف ارزیابی به عنوان تفسیر: برای ارزیابی یک لیست که نام تابع دارد، eval ابتدا تمام آرگومان‌های داده شده به cdr اش را ارزیابی می‌کند و سپس تابع را روی آن آرگومان‌ها اعمال می‌کند. در این مثال، تابع عمل جمع است و به آرگومان‌های (۱ ۲) اعمال می‌شود که نتیجه ۳ است. این نتیجهٔ ارزیابی است. این وظیفهٔ تابع print است که نتیجه را به کاربر نمایش دهد. برای نتیجهٔ سادهٔ ۳ این کار ناقابل است. یک عبارت که با قسمتی از ساختار لیست ارزیابی می‌شود میاز دارد که print لیست را به حرکت در آورد و در خروجی به شکل یک عبارت S نمایش دهد. برای اجرا کردن یک REPL در Lisp، تنها لازم است که این سه تابع را اجرا کنید و یک تابع حلقه بی‌نهایت را.(به طور طبیعی اجرای eval پس از اجرای عملگرهای ویژه‌ای مانند if پیچیده خواهد شد.)یک REPL ساده به خودی خود با یک خط کد انجام شد: (loop(print(eval(red))))

لیست در اصل تعداد کمی ساختار کنترلی دارد. منتها در تکامل و گسترش زبان تعداد زیادی به آن اضافه شدند.(عملگر اصلی شرایط در زبان Lisp که cond بود بعداً متشکل شد از ساختار if-then-else)

برنامه نویسان در نسخهٔ Scheme حلقه‌ها را به صورت بازگشت دم(tail recursion) بیان می‌کنند. موسسات متعارف علوم کامپیوتر Scheme بعضی دانشجویان را متعاقد می‌کند که تنها راه تکرار در زبان Lisp استفاده از بازگشت دم است؛ این اشتباه‌است. تمامی نسخه‌های متداول دیده شده از Lisp دارای ساختارهای الزامی برای تکرار هستند. درScheme دستور do به عنوان دستور حلقه پیچیدهٔ Lisp است. علاوه بر این مسالهٔ اصلی که شی گرایی را مهمتر از مسالهٔ فاعلی کرده این است که Scheme نیازهای ویژه‌ای برای کارکردن با فراخوانی دم(tail calls)دارد، در نتیجه دلیل ترغیب Scheme به استفاده از بازگشت دم این است که روش صراحتاً با تعریف خود زبان پشتیبانی می‌شود. در مقابل، ANSI Common Lisp نیازی به بهینه‌سازی که معمولاً به حذف فراخوانی دم گفته می‌شود ندارد. در نتیجه این حقیقت که بازگشت دم به عنوان یک جایگزین تصادفی برای استفاده از ساختارهای مبتنی بر تکرار (مانند do dolist loop) توصیه نمی‌شود تنها یک مسالهٔ برتری ادبی نیست، ولی بالقوه یکی از کارآمدهاست (بعد از این که این روش فقط به عنوان یک پرش ساده به کار نرفت) و به عنوان یک تصحیح برنامه‌است. بعضی از ساختارهای کنترلی Lisp عملگرهای ویژه‌ای هستند، هم ارز کلیدواژه‌های ترکیبی باقی زبان‌ها. عباراتی که این عملگرها استفاده می‌کنند ظاهری شبیه فراخوانی تابع دارد، تفاوت اینجاست که آرگومان‌ها ضرورتاً نباید ارزیابی شوند یا در مورد تکرار شاید بارها ارزیابی شوند. در مقابل اکثر زبان‌های برنامه نویسی، Lisp به برنامه نویسان اجازه می‌دهد با خود زبان ساختاهای کنترلی را پیاده‌سازی کنند. ساختارهای کنترلی زیادی در ماکروهای Lisp پیاده‌سازی می‌شوند و برنامه نویسان می‌توانند هر ماکرو را گسترش دهند، برای آنانی که می‌خواهند بدانند چطور کار می‌کند. هر دوی Lisp Common و Scheme دارای عملگرهای کنترلی غیر محلی هستند. تفاوت این عملگرها یکی از عمیق‌ترین تفاوت‌ها مابین این دو نسخهٔ زبان است. Scheme از ورودی مستمر با استفاده از روش call/cc پشتیبانی می‌کند، که به برنامه اجازهٔ ذخیره (و بعداً بازیابی کردن) یک عملیات ویژه را می‌دهد. Common Lisp از ورودی مستمر پشتیبانی نمی‌کند ولی از راه‌های زیادی برای انجام رهایی از تکرار پشتیبانی می‌کند.

جستارهای وابسته[ویرایش]

منابع[ویرایش]

  • Patrick Winston and Berthold Horn, Lisp, Addison Wesley; 3 edition (January 1, 1989), ISBN 0-201-08319-1