Code Corona
آموزش Scheme - بخش سوم - نسخه‌ی قابل چاپ

+- Code Corona (http://forum.codecorona.com)
+-- انجمن: Private Forum (http://forum.codecorona.com/forumdisplay.php?fid=24)
+--- انجمن: Portal Forum (http://forum.codecorona.com/forumdisplay.php?fid=25)
+--- موضوع: آموزش Scheme - بخش سوم (/showthread.php?tid=158)



آموزش Scheme - بخش سوم - melomane - 15-04-2007

فرم ها:
احتمالا تا اینجا متوجه شدید تمامی مثال هایی که از برنامه های اسکیم گفته شد به نوعی s-expression هستند. این برای تمامی برنامه ها در اسکیم صدق می کند:
برنامه ها هم در واقع داده هایی هستند.
از این رو داده ی کاراکتری #\c یک برنامه و یا بهتر بگوییم یک فرم است. ما به جای واژه ی برنامه از اصطلاح کلی تری به نام فرم استفاده می کنیم. بنابراین می توانیم با هر قطعه از برنامه کار کنیم.
اسکیم فرم #\c را به مقدار #\c ارزیابی می کند. چون #\c یک خود-ارزیاب است.
همانطور که در فصل قبل گفته شد منظور از یک فرم خود-ارزیاب فرمی است که حاصل ارزیابی آن مقداری مانند خود فرم است.
همه ی s-expressionها خود-ارزیاب نیستند. به عنوان مثال اگر یک s-expression از نوع سمبل با نام xyz ارزیابی شود حاصل مقداری است که متغیر xyz در خود دارد و یا s-expression : (string->number "16") به عدد 16 ارزیابی می شود.
همه ی s-expression ها به عنوان یک برنامه معتبر نیستند. اگر شما در listener یک s-expression از نوع dotted-pair تایپ کنید مثلا (1 . 2) با پیغام خطا مواجه خواهید شد.
اسکیم یک لیست از فرم ها را بر اساس اولین عنصر فرم (در اصطلاح راس فرم) ارزیابی می کند. اگر راس فرم به یک روال ارزیابی شود بقیه ی فرم به عنوان آرگومان های روال در نظر گرفته می شود. به این ترتیب روال بر آرگومان های ورودی اش اعمال می شود. اگر راس فرم یک نوع خاص باشد ارزیابی به صورت جداگانه روی فرم اعمال می شود. چند فرم خاص که تا اینجا با آن ها آشنا شدیم begin و define و set! هستند. begin باعث می شود زیر-فرم هایش به ترتیب و دنباله وار ارزیابی شوند.define متغیرها را تعریف و مقداردهی اولیه می کند. set! نیز یک متغیر را تغییر می دهد.


RE: آموزش Scheme - بخش سوم - melomane - 16-04-2007

روال ها:
تا اینجا چند روال از پیش تعریف شده در اسکیم را دیدیم مانند cons و string->number و ...
اما کاربران نیز می توانند با استفاده از فرم خاص lambda روال هایی برای خود بنویسند.برای مثال روال زیر 2 را با آرگومان ورودی خود جمع می کند.
کد:
(lambda (x) (+ x 2))

زیر فرم اول، (x) ، لیست آرگومان هاست. زیر فرم(های) باقیمانده بدنه ی روال را می سازد. این روال نیز مانند یک روال از پیش تعریف شده می تواند برای یک آرگومان ورودی فراخوانی شود.
کد:
((lambda (x) (+ x 2)) 5)
=>  7

اگر ما می خواستیم این روال را چندین بار فراخوانی کنیم می توانستیم عین این روال را چند بار بنویسیم. اما راه بهتری برای جلوگیری از نوشتن یک روال برای چندین بار وجود دارد.
می توان یک متغیر تعریف کرد که مقدرا آن تعریف روال است.
(define add2
(lambda (x) (+ x 2)))

اکنون دیگر نیازی به تعریف مجدد روال برای هر بار استفاده نیست. هر بار برای استفاده از متغیر add2 استفاده می کنیم:
(add2 4) => 6
(add2 9) => 11
پارامترهای روال:
پارامترهای روال های ساخته شده با lambda به وسیله ی اولین زیر فرم مشخص می شوند. (اولین زیر فرم بعد از سمبل lambda). add2 یک روال تک آرگومانی است بنابراین لیست آرگومان های آن فقط یک لیست تکی است. در اینجا سمبل x مانند متغیری عمل می کند که مقدار آرگومان ورودی روال را در خود دارد. تغییرات x در بدنه ی روال تنها به آرگومان ورودی بازمی گردد. متغیر x برای روال یک متغیر محلی (local) است.
می توان از یک لیست دو عنصری برای پارامترهای یک روال دو آرگومانی استفاده کرد. و در حالت کلی از یک لیست n عنصری برای یک روال با n آرگومان. مثال زیر یک روال با دو آرگومان را نشان می دهد که مساحت یک مستطیل را محاسبه می کند. آرگومان های ورودی طول و عرض مستطیل هستند:
(define area
(lambda (length breadth)
(* length breadth)))
همانطور که دیدید روال area تنها دو عدد را در هم ضرب می کند، یعنی همان کاری که روال از پیش تعریف شده ی * انجام می دهد. پس می توان به سادگی نوشت:
(define area *)
تعداد مقادیر آرگومان ها:
بعضی از روال ها می توانند در هر بار فراخوانی تعداد متفاوتی آرگومان ورودی داشته باشند. برای این کار پارامترهای lambda با یک سمبل جایگذاری می شود. این سمبل مانند متغیری عمل می کند که مقید به لیست آرگومان هایی است که روال برای آن فراخوانی می شود.
در حالت کلی، لیست پارامترهای lambda می تواند یک لیست به فرم (x ...)، یک سمبل، یک dotted pair به فرم (x ... . z) باشد. در حالت dotted-pair، متغیرهای قبل از نقطه مقید به آرگومان های متناظر به هنگام فراخوانی روال هستند و متغیر آخر تمام آرگومان های باقیمانده را به عنوان یک لیست می گیرد.
apply:
روال apply در اسکیم به ما اجازه می دهد تا یک روال را برای لیست آرگومان هایش فراخوانی کنیم:
(define x '(1 2 3))

(apply + x)
=> 6
در حالت کلی، apply یک روال به همراه تعداد متغیری از آرگومان را می گیرد که آخرین آن ها حتما یک لیست است. روال apply لیست آرگومان ها را با پیشوند قرار دادن آرگومان آخر با سایر آرگومان ها می سازد. سپس مقدار حاصل از فراخوانی روال را برمیگرداند. برای نمونه:
(apply + 1 2 3 x)
=> 12
دنباله سازی:
دیدیم که فرم خاص begin برای قراردان دسته ای از زیر فرم ها در یک گروه است که باید به ترتیب ارزیابی شوند. بسیاری از فرم ها در اسکیم begin را به صورت غیر آشکار در خود دارند. برای نمونه بیایید یک روال با 3 آرگومان ورودی تعریف کنیم. می خواهیم این آرگومان سه مقدار گرفته شده را با فاصله ای بین هر کدام نمایش دهد. یک تعریف صحیح برای این روال می تواند به صورت زیر باشد:
(define display3
(lambda (arg1 arg2 arg3)
(begin
(display arg1)
(display " ")
(display arg2)
(display " ")
(display arg3)
(newline))))

در اسکیم بدنه ی lambda به طور غیر آشکار begin را در خود دارد. بنابراین هر چند مانند مثال بالا بودن آن اشکالی ایجاد نمی کند اما می توان این روال را با حذف begin به طور ساده تر نوشت:
(define display3
(lambda (arg1 arg2 arg3)
(display arg1)
(display " ")
(display arg2)
(display " ")
(display arg3)
(newline)))