این تمرین «دستورهای شرطی» را معرفی میکند: انتخاب بین دو یا چند مسیر اقدام بر اساس یک مقدار. این تمرین بر «مقادیر منطقی» بنا شده است؛ همانهایی که در نفوذ آنالین دیدید، بههمراه محاسبات اعداد صحیح از تبدیل ارز.
همهی اینها در math قرار دارند (و = در kernel):
= ( x y -- ? ) ! equal
< ( x y -- ? ) ! less than
<= ( x y -- ? ) ! less than or equal
> ( x y -- ? ) ! greater than
>= ( x y -- ? ) ! greater than or equal
3 3 = . ! => t
2 3 < . ! => t
3 3 <= . ! => t
3 4 = not . ! => t (inequality: combine = with not)
zero? (در math) صورت کوتاه آزمون رایج 0 = است. عدد را مصرف میکند و اینکه صفر بوده یا نه را روی «پشته» میگذارد:
zero? ( n -- ? ) ! t when n is 0
between? (در math.order) آزمون میکند که آیا یک مقدار در یک بازهی بسته قرار میگیرد یا نه. وقتی یک کنش بستگی دارد به اینکه یک عدد در کدام بازه میافتد، این واژه به کار میآید:
between? ( x lo hi -- ? ) ! lo <= x <= hi (inclusive)
5 1 10 between? . ! => t
0 1 10 between? . ! => f
10 1 10 between? . ! => t (inclusive at both ends)
اغلب آن را بهعنوان «محمول» cond میبینید (dup 1 4 between?) تا شاخه را بر اساس بازه انتخاب کنید، نه بر اساس یک مقدار تنها.
واژههای مقایسهی بالا مقادیر منطقی تولید میکنند؛ برای اینکه روی یک مقدار منطقی کاری انجام دهید، باید یک یا چند «نقلقول» به دستور شرطی بدهید. یک «نقلقول» تکهکدی است که در «کروشه» پیچیده شده است: [ ... ]. نوشتن آن، کد را بهجای اجرا کردن بهعنوان یک مقدار روی پشته میگذارد؛ سپس واژهای مانند if تصمیم میگیرد که کدام نقلقول اجرا شود.
[ neg ] ! a quotation that negates the top of the stack
[ ] ! the empty quotation — does nothing
تمرین بعدی نقلقولها را بهطور کامل بررسی میکند؛ فعلاً [ ... ] را بهمعنای «کدی که برای این شاخه باید اجرا شود» بخوانید.
if، when، unless
if (در kernel) یک مقدار منطقی و دو نقلقول میگیرد. وقتی مقدار منطقی «درست» باشد نقلقول اول را اجرا میکند و وقتی «غلط» باشد نقلقول دوم را:
if ( ? then-quot else-quot -- )
: abs ( x -- y ) dup 0 < [ neg ] [ ] if ;
when نقلقول خود را فقط وقتی مقدار منطقی «درست» باشد اجرا میکند؛ unless فقط وقتی «غلط» باشد:
when ( ? quot -- )
unless ( ? quot -- )
if*، when* و unless*
سه گونه در kernel مقدار منطقی را وقتی «درست» باشد، بهعنوان یک مقدار ارزشمند برای نگه داشتن در نظر میگیرند. این وقتی به کار میآید که یک واژه «یک مقدار، یا f» را برمیگرداند:
if* ( ? true false -- ) ! truthy: true is called WITH ? on stack
when* ( ? true -- ) ! truthy: true is called WITH ? on stack
unless* ( ? false -- ) ! falsy: false runs and pushes a default
if* شکل دوشاخهای است. شاخهی «درست» با مقداری که هنوز روی پشته است فراخوانی میشود؛ شاخهی «غلط» بدون آن فراخوانی میشود:
42 [ ] [ "nothing" ] if* . ! prints 42
f [ ] [ "nothing" ] if* . ! prints "nothing"
unless* الگوی متعارف «مقدار یا مقدار پیشفرض» است. اگر مقدار «درست» باشد، دستنخورده رها میشود؛ اگر f باشد، مقدار حذف میشود و نقلقول اجرا میشود تا یک جانشین روی پشته بگذارد:
"hello" [ "anonymous" ] unless* . ! => "hello"
f [ "anonymous" ] unless* . ! => "anonymous"
when* شکل یکشاخهای if* است: نقلقول خود را (در حالی که مقدار هنوز روی پشته است) فقط وقتی مقدار «درست» باشد اجرا میکند و وقتی f باشد بهسادگی مقدار را حذف میکند. سراغش بروید تا نتیجهی «یک مقدار، یا f» را در یک مقدار جاری بگنجانید، بدون آنکه به سراغ حالت f بروید:
0 41 [ + ] when* . ! => 41 (truthy: 41 added to the running total)
0 f [ + ] when* . ! => 0 (falsy: f dropped, total left untouched)
condوقتی چند کنش جایگزین برای انتخاب دارید، cond (در combinators) انتخاب طبیعی است. این واژه آرایهای از جفتهای { predicate body } میگیرد و بدنهی نخستین محمولی را اجرا میکند که مقدار «درست» بدهد:
USING: combinators ;
: classify ( n -- label )
{
{ [ dup 0 < ] [ drop "negative" ] }
{ [ dup 0 = ] [ drop "zero" ] }
[ drop "positive" ]
} cond ;
چند نکته که ارزش توجه دارند:
dup ... <test> است.drop کردن ورودی و گذاشتن نتیجه شروع میشود.در این تمرین کدی مینویسید که تولید یک خط مونتاژ در کارخانهی خودروسازی را تحلیل کند. سرعت خط مونتاژ میتواند از 0 (خاموش) تا 10 (حداکثر) متغیر باشد.
در پایینترین سرعت غیرصفر (1)، هر ساعت 221 خودرو تولید میشود. تولید بهصورت خطی با سرعت افزایش مییابد، بنابراین در سرعت 4، خط مونتاژ هر ساعت 4 * 221 = 884 خودرو تولید میکند. با این حال، سرعتهای بالاتر احتمال تولید خودروهای معیوب را بیشتر میکنند، خودروهایی که بعد باید دور انداخته شوند.
شما چهار کار دارید. هر کدام یک پارامتر صحیح را از پشته برمیدارد که همان سرعت خط مونتاژ است.
production-status را طوری تعریف کنید که وقتی سرعت 0 است "stopped" و برای هر سرعت دیگری "running" برگرداند:
0 production-status .
! => "stopped"
3 production-status .
! => "running"
success-rate را طوری تعریف کنید که احتمال تولید یک خودرو بدون خطا را برگرداند:
0: 0.0
1 تا 4: 1.0
5 تا 8: 0.9
9: 0.8
10: 0.77
10 success-rate .
! => 0.77
production-rate-per-hour را طوری تعریف کنید که نرخ تولید خط مونتاژ در ساعت را با در نظر گرفتن نرخ موفقیت برگرداند.
اول باید base-speed را تعریف کنید، یعنی ثابت 221.
6 production-rate-per-hour .
! => 1193.4
مقداری که برگردانده میشود یک عدد اعشاری است.
working-items-per-minute را طوری تعریف کنید که برگرداند در هر دقیقه چند خودروی سالم تولید میشود. نتیجه یک عدد صحیح است؛ خودروهای ناقص شمرده نمیشوند.
6 working-items-per-minute .
! => 19