فهرست:
- قسمت اول : معرفی زبان برنامه نویسی لیسپ (Lisp)
- قسمت دوم : نوع داده های زبان برنامه نویسی لیسپ (Lisp) و زبان برنامه نویسی سی پلاس پلاس
- قسمت سوم : مقایسه ی کلی syntax در زبان برنامه نویسی LISP و ++C با مثال Hello world
- قسمت چهارم : مقایسه ی Binding در زبان LISP با ++C
- قسمت پنجم : نحوه ی استفاده از عملگر ها در زبان LISP و ++C
- قسمت ششم : مقایسه ی ویژگی های زبان LISP با ++C
- قسمت هفتم : یک کاریکاتور و یک نقل قول جالب در مورد قدرت و یک پارچگی LISP
- قسمت هشتم : یک ویدیو کوتاه در مورد بعضی از قابلیت ها و ویژگی ها LISP
قسمت اول : معرفی زبان برنامه نویسی لیسپ (Lisp)
Lisp (لیست) یک دسته از زبان های برنامه نویسی است که شامل چند زبان برنامه نویسی است با تاریخچه ای طولانی ، که همه چیز در آن به صورت پرانتز گذاری شده و با نمایش prefix notation است که در سال ۱۹۵۸ ساخته شد.
Lisp از نظر قدمت دومین زبان برنامه نویسی سطح بالا (high-level programming language ) است که امروزه هم مورد استفاده قرار می گیرد. فقط زبان فورتن در زبان های سطح بالایی که هنوز استفاده می شوند از لیسپ قدیمی تر است.
معروف ترین زبان های برنامه نویسی خانواده ی لیسپ زبان برنامه نویسی Common Lisp و Scheme است.
لیسپ برای اهداف ریاضی درست شده بود که از روش علامت گذاری حسابگر lambda آقای Alonzo Church استفاده می کرد.
لیسپ به سرعت به زبانی برای کارهای تحقیقاتی هوش مصنوعی تبدیل شد و مورد توجه محققان در این زمینه قرار گرفت.
لیسپ که یکی از اولین زبان های ساخته شده بود در بسیاری از زمینه های علم کامپیوتر پیشگام بود که در زیر بعضی از آن ها را مشاهده می کنید:
- ساختمان دادهای درخت ( tree data structures)
- مدیریت ذخیره سازی اتوماتیک (automatic storage management)
- نوع داده ای پویا (dynamic typing)
- دستورهای شرطی (conditionals)
- تابع های سطح بالا ( higher-order functions)
- تابع های بازگشتی (recursion)
- self-hosting compile (معادل فارسی پیدا نکردم)
اسم “Lisp” از عبارت “Linked List Processing” به دست آمده است. لیست پیوندی (Linked List) یکی از مهم ترین ساختمان داده ها در زبان لیسپ است و خود سورس کد زبان لیسپ هم لیست است.
زبان برنامه نویسی لیسپ کد یک برنامه ی نوشته شده را می تواند به عنوان یک ساختمان داده ی لیست بگیرد و آن را پردازش کند و تغییراتی روی آن انجام دهد در واقع زبان برنامه نویسی لیسپ می تواند یک کد زبان لیسپ بسازد!
تاریخچه ی Lisp :
لیسپ توسط پروفسور جان مک کارتی (John McCarthy) بزرگ در سال ۱۹۵۸، زمانی که در دانشگاه MIT بود اختراع شد. مک کارتی در آن سال ۱۹۶۰ در Communications of the ACM مقاله ای با عنوان “Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I””در مورد طراحی زبان لیسپ چاپ کرد (بخش دوم آن هیچ گاه چاپ نشد).
او در مقاله هاش نشان داد که با چند عملگر ساده و یک علامت گذاری برای تابع می توان یک زبان تورینگ کامل (Turing-complete) ساخت.
لیسپ اولین بار توسط استیو راسل (Steve Russell) روی کامپیوتر IBM 704 پیاده سازی شد. راسل مقاله ی مک کارتی خوانده بود و باور داشت که می توان آن را روی ماشین پیاده سازی کرد. نتیجه ی کار او مفسر لیسپی بود که می توانست برای اجرای دستورات لیسپ استفاده شود.
اولین کامپایلر کامل زبان لیسپ در سال ۱۹۶۲ توسم تیم هارت (Tim Hart) و مایک لوین (Mike Levin) در دانشگاه MIT ساخته شد . زبان استفاده شده در یادداشت های لوین و هارت به لیسپ مدرن امروزی بسیار نزدیک تر است تا لیسپ مک کارتی.
پیاده سازی سیستم لیسپ با تکنیک های کامپایل و سخت افزار دهه ی ۱۹۷۰ کار بسیار مشکلی بود. در سال های ۱۹۸۰ تا ۱۹۹۰ بزرگترین تاثیر رو خانواده ی لیسپ رخ داد و آن یکی کردن بسیاری از لیسپ های ساخته شده بود که منجر به ساخته شده زبان جدید Common Lisp شد.
در شکل زیر نموداری زمانی شکل گیری زبان های عضو خانواده ی لیسپ را می بینید.
قسمت دوم : نوع داده های زبان برنامه نویسی لیسپ (Lisp) و زبان برنامه نویسی سی پلاس پلاس
همین طور که در مقدمه بررسی کردیم زبان لیسپ بیشتر برای کار های محاسباتی و هوش مصنوعی طراحی شده است ، در زبان های برنامه نویسی هوش مصنوعی ما بیشتر از بر نوع داده های عددی به سیمبول ها احتیاج داریم تا عبارات منطقی و گزاره ها را بررسی کنیم.به طور کلی نوع داده در زبان برنامه نویسی لیسپ به صورت زیر است:
- نوع داده های عددی
- نوع داده ای کاراکتر
- نوع داده های منطقی
- نوع داده ای سمبول
نوع داده ای عددی در لیسپ: نوع داده ای عددی در لیسپ شامل اعداد صحیح ، ممیز شناور ، مختلط و کسری است.لیسپ معمولی از bignums برای نشان دادن مقدارهای عددی با دقت و اندازه دلخواه استفاده میکند. نوع کسری، کسرها را با دقت نشان میدهد، این ویژگی در بسیاری از زبانها وجود ندارد. لیسپ معمولی به صورت اتوماتیک مقدارهای عددی را بین این دادهها به صورت مناسب وارد میکند. در لیسپ می توان با اعداد خیلی بزرگ کار کرد بدون اینکه نگران سر ریز آن ها بود زیرا لیسپ یک رنج بزرگ را در اختیار می گذارد. در اسکرین شاتی که گرفتم انواع نوع داده ای عددی را در لیسپ می بینید:
همین طور که در شکل بالا می بینید جذر عدد منفی چهار را به صورت عدد مختلط چاپ کرده است.
نوع داده ای کاراکتر : در لیسپ نوع داده ی دیگری به نام کاراکتر داریم که فقط محدود به اعداد اسکی نیست و یونی کد ها را هم در بر می گیرد. برای تعریف داده های کاراکتری باید از # استفاده کرد مانند تصویر زیر که چند نوع داده ی کاراکتری را مشخص کرده ام:
در بالا tab# همان کاراکتر Tab است.
نوع دادده ای منطقی: در لیسپ نوع منطقی هم داریم که دو حالت درست و غلط را دارد.حالت درست را با true و حالت غلط را با NIL یا () نشان نی دهیم . در شکل زیر من تابع Listp را فرا خوانده ام که خروجی اش یک مقدار منطقی است و می گوید چیزی که تابع رویش فراخوانی شده است لیست است یا نه:
نوع داده ای سمبول: مهم ترین نوع داده ای در لیسپ نوع سمبول است که در هوش مصنوعی , پردازش زبان های طبیعی و … از آن استفاده می کنیم. در شکل زیر لیستی از سمبول ها ساخته ام:
نوع داده ها در زبان برنامه نویسی سی پلاس پلاس را هم در پایین می بینید:
Type Name | Bytes | Other Names | Range of Values |
---|---|---|---|
int | ۴ | signed | –۲,۱۴۷,۴۸۳,۶۴۸ to 2,147,483,647 |
unsigned int | ۴ | unsigned | ۰ to 4,294,967,295 |
__int8 | ۱ | char | –۱۲۸ to 127 |
unsigned __int8 | ۱ | unsigned char | ۰ to 255 |
__int16 | ۲ | short, short int, signed short int | –۳۲,۷۶۸ to 32,767 |
unsigned __int16 | ۲ | unsigned short, unsigned short int | ۰ to 65,535 |
__int32 | ۴ | signed, signed int, int | –۲,۱۴۷,۴۸۳,۶۴۸ to 2,147,483,647 |
unsigned __int32 | ۴ | unsigned, unsigned int | ۰ to 4,294,967,295 |
__int64 | ۸ | long long, signed long long | –۹,۲۲۳,۳۷۲,۰۳۶,۸۵۴,۷۷۵,۸۰۸ to 9,223,372,036,854,775,807 |
unsigned __int64 | ۸ | unsigned long long | ۰ to 18,446,744,073,709,551,615 |
bool | ۱ | none | false or true |
char | ۱ | none | –۱۲۸ to 127 by default0 to 255 when compiled with /J |
signed char | ۱ | none | –۱۲۸ to 127 |
unsigned char | ۱ | none | ۰ to 255 |
short | ۲ | short int, signed short int | –۳۲,۷۶۸ to 32,767 |
unsigned short | ۲ | unsigned short int | ۰ to 65,535 |
long | ۴ | long int, signed long int | –۲,۱۴۷,۴۸۳,۶۴۸ to 2,147,483,647 |
unsigned long | ۴ | unsigned long int | ۰ to 4,294,967,295 |
long long | ۸ | none (but equivalent to __int64) | –۹,۲۲۳,۳۷۲,۰۳۶,۸۵۴,۷۷۵,۸۰۸ to 9,223,372,036,854,775,807 |
unsigned long long | ۸ | none (but equivalent to unsigned __int64) | ۰ to 18,446,744,073,709,551,615 |
enum | varies | none | See Remarks. |
float | ۴ | none | ۳٫۴E +/- 38 (7 digits) |
double | ۸ | none | ۱٫۷E +/- 308 (15 digits) |
long double | same as double | none | same as double |
wchar_t | ۲ | __wchar_t | ۰ to 65,535 |
قسمت سوم : مقایسه ی کلی syntax در زبان برنامه نویسی LISP و ++C با مثال Hello World
برنامه ی سلام دنیا در زبان برنامه نویسی سی پلاس پلاس :
// "Hello, World!" written in C++ int main() { std::cout << "Hello, world!n"; }
برنامه ی سلام دنیا در زبان برنامه نویسی لیسپ:
(print "hello world")
قسمت چهارم : مقایسه ی Binding در زبان LISP با ++C
زبان لیسپ یک زبان برنامه نویسی Late Binding است . یعنی متغییر ها احتیاجی به تعریف کردن ندارند و لازم نیست بگوییم یک متغییر از نوع int است! و هر زمان از برنامه هر چیز را که بخواهیم می توانیم در آن ها بریزیم.
به مثال زیر نگاه کنید.
من بار اول متغییر var را یک عدد صحیح گذاشته ام:
(defparameter var 5)
و بار دیگر در آن یک رشته ریخته ام
(defparameter var "Hello")
و در بار سوم در آن داده از نوع complex در آن ریخته ام
(defparameter var #c(0.0 -2.3))
ولی سی پلاس پلاس از نوع early Binding است . یعنی متغییر ها باید نوعشان معرفی شود و تا آخر برنامه نوعشان ثابت می ماند و نمی توان چیز دیگری در آن ریخت در غیر این صورت خطا می دهد.
مثال زیر تعریف یک متغییر صحیح را در سی پلاس پلاس نشان می دهد:
int num;
قسمت پنجم : نحوه ی استفاده از عملگر ها در زبان LISP و ++C
در زبان لیسپ استفاده از عملگر ها به صورت Prefix یا پیش ترتیب است که با سایر زبان های برنامه نویسی فرق دارد در این روش ابتدا عملگر می آید و بعد در جلوی آن عملوند ها . مزیتی که این روش دارد این است که تعداد عملگر هایمان محدود نمی شود.
در مثال زیر من ۵ عدد مختلف را در زبان لیسپ فقط با یک عملگر + ، جمع کرده ام:
(+ 5 4 8 9 7)
در زبان سی پلاس پلاس عملگرها به صورت In order یا میان ترتیب استفاده می شوند و بین دو مقدار مختلف می آیند.
در مثال زیر من پنج عدد بالا را در زبان سی پلاس پلاس جمع کرده ام :
int sum = 5 + 4 + 8 + 9 + 7;
قسمت ششم : بررسی ویژگی های زبان LISP
۱) وضوح ، سادگی ، یکپارچه بودن:
زبان لیست یک زبان بسیار یکپارچه و ساده و با وضوح خیلی بالا است به طوری که استفاده از تابع و عملگر و … کاملا شبیه هم است و این یک یکپارچگی تا حدی بالاست که خیلی راحت می توان با یک برنامه ی زبان لیسپ یک برنامه ی زبان لیسپ دیگر ایجاد کرد.
یک نقل قول در مورد وضوح و شفافیت زبان لیسپ از زبان یکی از بیان گذاران دنیای متن باز:
You can use C++ if you want with GNOME, but we don’t assume that you’re going to write C++. It’s to a large extent based on Scheme, which is a dialect of LISP. LISP being the most powerful and cleanest of languages, that’s the language that’s the GNU project always prefers.
Richard Stallman in: “GNU’s Not Linux” Network World Fusion, 01/11/99.
۲) تعامد (orthogonality):
همین طور که در بالا اشاره کردم می توان خیلی از دستورات و کار ها را شبیه هم در زبان لیسپ انجام داد و آن به خاطر استفاده از ساختار لینک لیست و نمایش پیش ترتیب است.
۳) معنائی بودن
لیسپ بسیار به زبان محاوره ای نزدیک است و وقتی کد زبان لیسپ می زنید احساس می کنید در حال مکالمه ی انگلیسی با کامپیوتر هستید مثالا در کد زیر من خواسته ام عنصر اول و چهارم لیست را برگردانم:
(first '(a b c d))
(forth '(a b c d))
۴) انتزاعی بودن (Abstraction)
در لیسپ امکان ساخت نوع داده ی جدید وجود دارد ولی مانند زبان سی پلاس پلاس امکان تعریف تابع در کلاس و اعضای Public و private را نداریم.
در زیر تعریف یک کلاس را در استراکت را در لیسپ می بینید و همین طور ساخت یک شی از آن را:
(defstruct dog name breed age) (defparameter *rover* (make-dog :name "rover" :breed "collie" :age 5))
۵) قابلیت انتقال
زبان لیسپ روی تمام سیستم عامل ها و پردازنده ها اجرا می شوند و مانند سی پلاس پلاس Portable است و قابلیت انتزاع بالایی دارد.
۶) سادگی تایید برنامه
زبان لیسپ یک زبان تابعی است و همین قابلیت تعامد و طبیعی بودنش هم بالاست و تقریبا استثنا در سینتکس نداریم. در نتیجه به راحتی می شود یک برنامه زبان لیسپ را فهمید و درستی آن را تایید کرد.
قسمت هفتم : یک کاریکاتور و نقل قول جالب در مورد قدرت و یک پارچگی LISP
کاریکاتور زیر توسط یکی از مجلات معروف در زمینه ی علوم کامپیوتر منتشر شده است . متاسفانه اسم آن مجله را بیاد ندارم تا به آن لینک دهم.
(برای دیدن در اندازه ی واقعی روی عکس کلیلک کنید)
God wrote in Lisp code
When he filled the leaves with green.
The fractal flowers and recursive roots:
The most lovely hack I’ve seen.
- Bob Kanefsky, “Eternal Flame”
برای دین نقل قول های دیگر از طرف بزرگان دنیای کامپیوتر به این آدرس بروید.
قسمت هشتم : یک ویدیو کوتاه در مورد بعضی از قابلیت ها و ویژگی ها LISP
معرفی بعضی از ویژگی های زبان برنامه نویسی لیسپ :