Scheme یک گویش مینیمالیستی از زبان برنامهنویسی Lisp است که برای تسهیل سبک برنامهنویسی تابعی طراحی شده و در عین حال یک نحو ساده و تمیز را ترویج میکند. این زبان با استفاده از پرانتزها، یک سیستم ماکرو قدرتمند و تأکید قوی بر بازگشت و رویههای درجه یک مشخص میشود. این زبان یک پارادایم برنامهنویسی تابعی را تشویق میکند و از تکنیکهای برنامهنویسی مختلفی از جمله برنامهنویسی تابعی، دستوری و منطقی پشتیبانی میکند.
Scheme در دهه 1970 توسط جرالد جی ساسمن و گای ال. استیل جونیور در مؤسسه فناوری ماساچوست (MIT) ایجاد شد. این زبان به عنوان تلاشی برای سادهسازی و بهبود زبان اصلی Lisp توسعه یافت که در طول زمان پیچیده شده بود. انگیزه پشت Scheme ایجاد زبانی بود که پیادهسازی و آموزش آن آسانتر باشد و در عین حال به اندازه کافی قدرتمند باشد تا ایدههای پیچیده را بیان کند.
در طول سالها، Scheme تحت بازنگریها و تلاشهای استانداردسازی مختلفی قرار گرفته است. از مهمترین این استانداردها میتوان به RnRS (گزارشهای اصلاحشدهn در مورد زبان الگوریتمی Scheme) اشاره کرد که زبان و ویژگیهای آن را رسمی کرد. جامعه Scheme از آن زمان به توسعه زبان ادامه داده است و به استانداردهای جدیدتری مانند R6RS و R7RS منجر شده است که ویژگیها و بهبودهای جدیدی را معرفی کردند.
در حال حاضر، Scheme در محیطهای دانشگاهی، به ویژه در آموزش علوم کامپیوتر، به دلیل زیبایی و نحو تمیز آن محبوب باقی مانده است. تأثیر آن را میتوان در بسیاری از زبانها و پارادایمهای برنامهنویسی مدرن مشاهده کرد. Scheme اغلب با جامعه برنامهنویسی تابعی مرتبط است و الهامبخش زبانهایی مانند Clojure و Racket بوده است که بر اصول آن بنا شده و قابلیتهای آن را گسترش دادهاند.
Scheme از یک نحو کاملاً پرانتزی استفاده میکند که در آن کد به صورت نوتیشن پیشوند نوشته میشود؛ به عنوان مثال، یک عملیات جمع به صورت (+ 1 2)
نوشته میشود.
توابع در Scheme شهروندان درجه یک هستند، به این معنی که میتوان آنها را به عنوان آرگومانها منتقل کرد یا از توابع دیگر بازگرداند. مثال:
(define (make-adder x)
(lambda (y) (+ x y)))
(define add5 (make-adder 5))
(add5 10) ; برمیگرداند 15
Scheme از بهینهسازی تماس دمی پشتیبانی میکند و به توابع اجازه میدهد تا از فریم پشته فعلی برای تماسهای بازگشتی که در موقعیت دمی رخ میدهند، استفاده کنند و از سرریز پشته جلوگیری کنند.
Scheme اجازه استفاده از ادامهها را میدهد و به برنامهنویسان این امکان را میدهد که وضعیت فعلی محاسبات را ضبط کرده و جریان کنترل را دستکاری کنند:
(call-with-current-continuation
(lambda (exit)
(exit 'done)))
Scheme دارای یک سیستم ماکرو قدرتمند است که به برنامهنویسان اجازه میدهد تا گسترشهای نحوی ایجاد کنند. یک ماکرو ساده میتواند به صورت زیر تعریف شود:
(define-syntax my-if
(syntax-rules ()
((_ test then else)
(if test then else))))
Scheme از انتزاع داده از طریق ساختارهایی مانند لیستها، جفتها و توابع مرتبه بالاتر پشتیبانی میکند و امکان دستکاری کارآمد دادهها را فراهم میآورد.
Scheme از دامنه لغوی استفاده میکند، جایی که دامنه یک متغیر بر اساس موقعیت فیزیکی آن در کد منبع تعیین میشود. این منجر به رفتار قابل پیشبینی در مورد پیوندهای متغیر میشود.
Scheme نوعگذاری پویا دارد و به متغیرها اجازه میدهد تا مقادیر هر نوعی را بدون نیاز به اعلام نوع صریح نگه دارند.
به عنوان یک گویش Lisp، Scheme برای پردازش لیست بهینهسازی شده است و انجام عملیات بر روی لیستها را آسان میکند:
(define my-list (list 1 2 3 4))
(car my-list) ; برمیگرداند 1
(cdr my-list) ; برمیگرداند (2 3 4)
توابع Scheme میتوانند به صورت بازگشتی با موقعیت دمی تعریف شوند تا استفاده از حافظه و عملکرد را بهینه کنند. به عنوان مثال:
(define (factorial n)
(define (fact-helper n acc)
(if (zero? n)
acc
(fact-helper (- n 1) (* n acc))))
(fact-helper n 1))
برنامههای Scheme معمولاً میتوانند با استفاده از محیط زمان اجرای پیادهسازی انتخاب شده ساخته شوند. به عنوان مثال، در Racket، میتوانید از ابزار خط فرمان racket
برای اجرای فایلهای .rkt
یا کامپایل آنها به فایلهای اجرایی استفاده کنید.
چندین کامپایلر و مفسر برای Scheme در دسترس است، از جمله:
Scheme به طور گستردهای در دانشگاهها برای آموزش اصول برنامهنویسی و به عنوان ابزاری برای تحقیق در علوم کامپیوتر استفاده میشود. این زبان در هوش مصنوعی، طراحی زبان و اسکریپتنویسی، و همچنین در حوزههای مختلفی که نیاز به محاسبات نمادین یا دستکاری دادههای پیچیده دارند، کاربرد دارد.
هر دو زبان از سبک برنامهنویسی تابعی پشتیبانی میکنند، اما Python بر خوانایی و سادگی تأکید دارد، در حالی که Scheme بر عبارات قدرتمند و مختصر تمرکز میکند. نحو پرانتز محور Scheme ممکن است به عنوان یک مانع برای مبتدیان دیده شود، در حالی که نحو مبتنی بر تورفتگی Python به طور کلی قابل دسترسیتر است.
JavaScript همچنین از برنامهنویسی تابعی پشتیبانی میکند و دارای توابع درجه یک است. با این حال، JavaScript دارای یک سیستم شیء مبتنی بر پروتوتایپ است، در حالی که Scheme به پارادایمهای تابعی تکیه دارد. سیستم ماکرو Scheme قابلیتهایی را ارائه میدهد که در JavaScript وجود ندارد.
C یک زبان سطح پایین و نوعگذاری استاتیک است که برای برنامهنویسی سیستم طراحی شده است، در حالی که Scheme زبان سطح بالا و نوعگذاری پویا است. C بر عملکرد و دستکاری سطح سختافزار تمرکز دارد، در حالی که Scheme بر انتزاع و جنبههای نظری محاسبات تأکید میکند.
هر دو زبان ریشه در برنامهنویسی تابعی دارند. Haskell از یک سیستم نوع سختگیرانهتر استفاده میکند و از ارزیابی تنبل پشتیبانی میکند، در حالی که نوعگذاری پویا و ارزیابی مشتاق Scheme امکان برنامهنویسی انعطافپذیرتری را فراهم میآورد که به هزینه برخی از عملکردها است.
Ruby یک زبان برنامهنویسی شیءگرا است که ویژگیهای برنامهنویسی تابعی را ترکیب میکند، در حالی که Scheme به طور خالص تابعی است. نحو Ruby بیشتر توصیفی است، در حالی که سادگی Scheme ناشی از طراحی مینیمالیستی آن است.
ترجمه کد Scheme به زبانهای دیگر میتواند با استفاده از ابزارهایی که هم نحو Scheme و هم زبان هدف را درک میکنند، تسهیل شود. برخی از ابزارهای مفید ترجمه کد از منبع به منبع شامل:
Chicken Scheme یک کامپایلر ارائه میدهد که میتواند کد Scheme را به C ترجمه کند و این امکان را فراهم میآورد که از کتابخانههای C استفاده کرده و فایلهای اجرایی کارآمد ایجاد کند.
Racket، یک مشتق از Scheme، دارای قابلیتهای داخلی برای تبدیل و کامپایل کد به JavaScript است که استقرار برنامههای وب را آسانتر میکند.
Gambit Scheme میتواند کد Scheme را به C و فایلهای اجرایی بومی کامپایل کند و گزینههای ترجمه کارآمدی را برای برنامههای حساس به عملکرد فراهم میآورد.