درس ۸ از ۴۹ · جریان برنامه

همخوان و ترابرد

وقتی یک مقدار چند حالت ممکن دارد، به‌جای زنجیره‌ای از اگرها از همخوان یا ترابرد استفاده کنید. همخوان مقدار را با الگوها می‌سنجد و بررسی می‌کند که هیچ حالتی از قلم نیفتاده باشد؛ ترابرد دستوری به سبک زبان C است، با بازه، مقایسه و ریزش به حالت بعد.

همخوان

همخوان یک عبارت است: مقدار را با حالت‌ها مقایسه می‌کند و نتیجه‌ی شاخه‌ی جورشده را برمی‌گرداند. هر شاخه یک الگوست، سپس دونقطه، نتیجه و پایان. چند حالت می‌توانند با ویرگول یک شاخه را شریک شوند و وگرنه همه‌ی حالت‌های دیگر را می‌گیرد.

match-values.salam
تابع رده(نمره: صحیح): رشته:
    برگشت همخوان نمره / ۱۰:
        ۱۰، ۹: "عالی" پایان
        ۸: "خیلی خوب" پایان
        ۷: "خوب" پایان
        وگرنه: "نیاز به تلاش" پایان
    پایان
پایان

تابع ریشه:
    سرچاپ رده(۹۵)، رده(۸۰)، رده(۴۵)
پایان
خروجیعالی خیلی خوب نیاز به تلاش

وقتی همخوان مقداری برمی‌گرداند، همه‌ی شاخه‌ها باید مقداری بدهند و همه از یک نوع.

همخوان به شکل دستور

همخوان می‌تواند به تنهایی و به شکل یک دستور هم بیاید. آن‌وقت هر شاخه می‌تواند چند خط داشته باشد که با پایان خودش بسته می‌شود. موضوع همخوانی لازم نیست عدد باشد: رشته هم می‌شود و با محتوایش سنجیده می‌شود. این مثال فهرستی از فرمان‌ها را یکی‌یکی اجرا می‌کند، مثل یک ابزار خط فرمان کوچک یا یک ربات گفتگو.

match-command.salam
تابع ریشه:
    فرمان‌ها := ["آغاز"، "وضعیت"، "توقف"، "پرش"، "خروج"]
    ناپایا روشن := نادرست
    هر فرمان در فرمان‌ها:
        همخوان فرمان:
            "آغاز"، "اجرا":
                روشن = درست
                سرچاپ "در حال آغاز"
            پایان
            "توقف":
                روشن = نادرست
                سرچاپ "در حال توقف"
            پایان
            "وضعیت":
                سرچاپ روشن ? "روشن" : "خاموش"
            پایان
            "خروج": سرچاپ "خدانگهدار" پایان
            وگرنه: سرچاپ "فرمان ناشناخته:"، فرمان پایان
        پایان
    پایان
پایان
خروجیدر حال آغاز روشن در حال توقف فرمان ناشناخته: پرش خدانگهدار

برخلاف ترابرد، شاخه‌ی همخوان هرگز به شاخه‌ی بعد نمی‌ریزد و دقیقا یک شاخه اجرا می‌شود. الگوی عدد یا رشته یک مقدار دقیق است. بازه‌ای مثل ۱ تا ۹ یا مقایسه‌ای مثل < ۰ الگوی همخوان نیست؛ برای این‌ها ترابرد را به کار ببرید که در ادامه می‌آید.

همخوانی جداشمار

روی جداشمار، الگوها نام حالت‌ها هستند. نام خالی بهار کافی است و شکل کامل فصل.بهار هم پذیرفته می‌شود. همخوان بررسی می‌کند که هیچ حالتی از قلم نیفتاده باشد:

match.salam
جداشمار فصل:
    بهار، تابستان، پاییز، زمستان
پایان

تابع هوا(ف: فصل): رشته:
    برگشت همخوان ف:
        بهار, پاییز: "معتدل" پایان
        تابستان: "گرم" پایان
        زمستان: "سرد" پایان
    پایان
پایان

تابع ریشه:
    سرچاپ "هوای بهار:", هوا(فصل.بهار)
    سرچاپ "هوای زمستان:", هوا(فصل.زمستان)
پایان
خروجیهوای بهار: معتدل هوای زمستان: سرد

اگر شاخه‌ی زمستان را بردارید، برنامه دیگر کامپایل نمی‌شود و پیام خطا حالت جاافتاده را نام می‌برد. پس وقتی بعدها حالتی به جداشمار می‌افزایید، مترجم همه‌ی همخوان‌هایی را که باید آن را بشناسند نشانتان می‌دهد. شاخه‌ی وگرنه این بررسی را خاموش می‌کند؛ پس هر جا می‌توانید همه‌ی حالت‌ها را بنویسید، آن را نگذارید.

بیرون کشیدن داده و نگهبان

وقتی حالت‌های جداشمار داده دارند، الگو می‌تواند آن داده را باز کند: نقد(م) مبلغ را در م می‌گذارد و _ از مقداری که لازم ندارید می‌گذرد. کارت ک کل حالت را به ک می‌دهد تا فیلدهایش را با ک.مبلغ بخوانید. هر شاخه می‌تواند نگهبان هم داشته باشد: اگر و یک شرط پس از الگو. نگهبان نام‌هایی را که الگو ساخته می‌شناسد و اگر نادرست باشد، همخوانی با شاخه‌ی بعدی ادامه پیدا می‌کند.

match-data.salam
جداشمار پرداخت:
    نقد(مبلغ: صحیح)
    کارت(مبلغ: صحیح، چهاررقم: رشته)
    بن(کد: رشته)
    رایگان
پایان

تابع رسید(پ: پرداخت): رشته:
    برگشت همخوان پ:
        نقد(م) اگر م >= ۱۰۰۰: "نقد " + م + "، دوباره بشمارید" پایان
        نقد(م): "نقد " + م پایان
        کارت(م، چهاررقم): "کارت با پایان " + چهاررقم + "، " + م پایان
        بن(_): "پرداخت با بن خرید" پایان
        رایگان: "پرداختی لازم نیست" پایان
    پایان
پایان

تابع ریشه:
    سرچاپ رسید(پرداخت.نقد(۱۵۰۰))
    سرچاپ رسید(پرداخت.نقد(۲۰))
    سرچاپ رسید(پرداخت.کارت(۸۰، "4421"))
    سرچاپ رسید(پرداخت.بن("BAHAR"))
    سرچاپ رسید(پرداخت.رایگان)
    پ := پرداخت.کارت(۳۵، "0042")
    برچسب := همخوان پ:
        کارت ک: "پرداخت کارتی به مبلغ " + ک.مبلغ پایان
        وگرنه: "نوع دیگری از پرداخت" پایان
    پایان
    سرچاپ برچسب
پایان
خروجینقد 1500، دوباره بشمارید نقد 20 کارت با پایان 4421، 80 پرداخت با بن خرید پرداختی لازم نیست پرداخت کارتی به مبلغ 35

شاخه‌ی نگهبان‌دار حالتش را به تنهایی پوشش نمی‌دهد؛ برای همین نقد(م) یک بار دیگر بی نگهبان آمده است. جداشمارهای داده‌دار در درس جداشمارها معرفی می‌شوند.

الگوی ساختار

همخوان می‌تواند یک ساختار را با فیلدهایش بسنجد. ایکس = ۰ یعنی فیلد باید برابر صفر باشد و نام تنها، مثل ایگرگ، مقدار فیلد را در متغیری به همان نام می‌گذارد. چون الگوها شرط دارند، یک وگرنه در پایان لازم است.

match-struct.salam
ساختار نقطه:
    همگانی ایکس: صحیح = ۰
    همگانی ایگرگ: صحیح = ۰
پایان

تابع جای(ن: نقطه): رشته:
    برگشت همخوان ن:
        نقطه { ایکس = ۰، ایگرگ = ۰ }: "مبدأ" پایان
        نقطه { ایکس = ۰، ایگرگ }: "روی محور عمودی، ایگرگ = " + ایگرگ پایان
        نقطه { ایکس، ایگرگ = ۰ }: "روی محور افقی، ایکس = " + ایکس پایان
        وگرنه: "جای دیگر" پایان
    پایان
پایان

تابع ریشه:
    سرچاپ جای(نقطه {})
    سرچاپ جای(نقطه { ایگرگ = ۵ })
    سرچاپ جای(نقطه { ایکس = ۳ })
    سرچاپ جای(نقطه { ایکس = ۱، ایگرگ = ۲ })
پایان
خروجیمبدأ روی محور عمودی، ایگرگ = 5 روی محور افقی، ایکس = 3 جای دیگر

ترابرد

ترابرد دستوری برای انتخاب میان حالت‌هاست. برچسب هر حالت می‌تواند یک مقدار، چند مقدار با ویرگول یا یک بازه مثل ۱ تا ۳ باشد. اگر حالتی با بشکن تمام نشود، اجرا به حالت بعدی هم می‌رود؛ پس هر جا نمی‌خواهید، بشکن بنویسید.

switch.salam
تابع ریشه:
    تکرار ۵ در روز:
        ترابرد روز:
            ۰:
                سرچاپ روز, "شنبه، آغاز هفته"
                بشکن
            پایان
            ۱ تا ۳:
                سرچاپ روز, "میانه‌ی هفته"
                بشکن
            پایان
            وگرنه:
                سرچاپ روز, "نزدیک تعطیلی"
            پایان
        پایان
    پایان
پایان
خروجی0 شنبه، آغاز هفته 1 میانه‌ی هفته 2 میانه‌ی هفته 3 میانه‌ی هفته 4 نزدیک تعطیلی

برچسب ترابرد می‌تواند با یک عملگر مقایسه شروع شود، مثل >= ۹۰. ترابرد درست هم جای زنجیره‌ی اگرها را می‌گیرد: هر برچسب یک شرط است و نخستین شرط درست اجرا می‌شود.

switch-true.salam
تابع ریشه:
    تکرار ۳ در ای:
        دما := ای * ۱۵
        ترابرد درست:
            دما < ۱۰:
                سرچاپ دما, "سرد"
                بشکن
            پایان
            دما < ۲۵:
                سرچاپ دما, "معتدل"
                بشکن
            پایان
            وگرنه:
                سرچاپ دما, "گرم"
            پایان
        پایان
    پایان
    نمره := ۷۵
    ترابرد نمره:
        >= ۹۰:
            سرچاپ "عالی"
            بشکن
        پایان
        >= ۶۰:
            سرچاپ "قبول"
            بشکن
        پایان
        وگرنه:
            سرچاپ "مردود"
        پایان
    پایان
پایان
خروجی0 سرد 15 معتدل 30 گرم قبول

ریزش عمدی به حالت بعد

ریزش به حالت بعد معمولا چیزی است که باید جلویش را گرفت، اما وقتی هر حالت چیزی به حالت‌های پایینی می‌افزاید به کار می‌آید. در این طرح اشتراک، طرح ویژه همه‌ی امکانات استاندارد را دارد و بیشتر، و استاندارد همه‌ی امکانات پایه را. اگر حالت‌ها را از کامل‌ترین به پایین بچینید و بشکن ننویسید، امکانات هر طرح بی تکرار فهرست می‌شود.

switch-fallthrough.salam
جداشمار طرح:
    پایه، استاندارد، ویژه
پایان

تابع امکانات(ط: طرح):
    سرچاپ "طرح"، ط.نام()، "شامل این‌هاست:"
    ترابرد ط:
        ویژه:
            سرچاپ "  دانلود برای تماشای آفلاین"
        پایان
        استاندارد:
            سرچاپ "  ویدیوی با کیفیت بالا"
        پایان
        پایه:
            سرچاپ "  همه‌ی فیلم‌ها و سریال‌ها"
        پایان
    پایان
پایان

تابع ریشه:
    امکانات(طرح.ویژه)
    امکانات(طرح.پایه)
پایان
خروجیطرح ویژه شامل این‌هاست: دانلود برای تماشای آفلاین ویدیوی با کیفیت بالا همه‌ی فیلم‌ها و سریال‌ها طرح پایه شامل این‌هاست: همه‌ی فیلم‌ها و سریال‌ها

ترابرد روی جداشمار باید همه‌ی حالت‌ها را پوشش دهد یا وگرنه داشته باشد؛ وگرنه خطای E103 می‌گیرد، درست مثل همخوان. ترابرد روی هر چیز دیگری که برچسب جوری پیدا نکند، به سادگی هیچ کاری نمی‌کند.

ترابرد درون حلقه

درون ترابرد، بشکن فقط از خود ترابرد بیرون می‌رود، نه از حلقه‌ی پیرامونش. برای بیرون رفتن از حلقه هم بشکن ۲ بنویسید. گذر را ترابرد نمی‌گیرد و یکراست به دور بعدی حلقه می‌رود. این مثال میانگین خوانده‌های یک حسگر را می‌گیرد، مقداری را که یعنی «حسگر خاموش است» کنار می‌گذارد و به نشانه‌ی پایان که می‌رسد می‌ایستد.

switch-loop.salam
تابع ریشه:
    خوانده‌ها := [۲۱، -۱، ۲۳، ۹۹۹، ۲۵، ۰، ۳۰]
    ناپایا جمع := ۰
    ناپایا شمار := ۰
    هر خ در خوانده‌ها:
        ترابرد خ:
            -۱:
                سرچاپ "حسگر خاموش است، رد شد"
                گذر
            پایان
            ۹۹۹:
                سرچاپ "نشانه‌ی پایان داده، توقف"
                بشکن ۲
            پایان
            وگرنه:
                جمع += خ
                شمار++
            پایان
        پایان
        سرچاپ "خوانده‌ی"، خ، "پذیرفته شد"
    پایان
    سرچاپ "میانگین"، شمار، "خوانده:"، جمع / شمار
پایان
خروجیخوانده‌ی 21 پذیرفته شد حسگر خاموش است، رد شد خوانده‌ی 23 پذیرفته شد نشانه‌ی پایان داده، توقف میانگین 2 خوانده: 22

همخوان یا ترابرد؟

وضعیتبه کار ببرید
یک مقدار برگشتی لازم داریدهمخوان
حالت‌های جداشمار داده دارند، یا نگهبان و الگوی ساختار لازم استهمخوان
بازه‌ای مثل ۱۰ تا ۱۹ یا برچسبی مثل >= ۹۰ترابرد
یک حالت باید به حالت بعدی ادامه پیدا کندترابرد بدون بشکن
چند دستور در هر حالت، روی جداشمار یا مقداری سادههر دو؛ هر دو پوشش کامل جداشمار را می‌سنجند
چند شرط بی‌ربط به همترابرد درست، یا همان اگر و وگرنه

آنچه باید به خاطر داشت

  • شاخه‌ی همخوان هرگز به بعدی نمی‌ریزد؛ حالت ترابرد همیشه می‌ریزد، مگر با بشکن تمام شود.
  • الگوی جداشمار نام حالت است، خالی (بهار) یا همراه با نام جداشمار (فصل.بهار).
  • همخوان روی جداشمار باید همه‌ی حالت‌ها را بپوشاند و ترابرد روی جداشمار هم (E103)، مگر وگرنه داشته باشند.
  • شاخه‌ی نگهبان‌دار، یا الگوی ساختاری که شرط دارد، به تنهایی حالتش را پوشش نمی‌دهد.
  • بشکن در ترابرد از ترابرد بیرون می‌رود و بشکن ۲ از حلقه‌ی پیرامونش هم.
  • در ترابرد، وگرنه باید آخرین برچسب باشد.