۷ - ۵بیانیههای case
مشابه if-then-else، بیانیههای case هم برای تعیین خروجیهای متفاوتِ توابع، بر اساس ورودیهای متفاوت به کار میرن. بیانیههای case با هر نوعدادهای که دادهسازهای مرئی (م. در گستره) داشته باشه قابل استفادهاند. نوعداده ِ Bool رو که بررسی کنیم:
data Bool = False | True
-- [1] [2] [3]۱.
نوعساز، که فقط در تایپ سیگنچرها استفاده میشه، و در کُدهای سطح جملهای مثل بیانیههای case استفاده نمیشه.
۲.
دادهساز برای مقداری از تایپِ Bool به اسمِ False – میشه روی این تطبیق داد.
۳.
دادهساز برای مقداری از تایپ Bool به اسم True – میشه روی این هم تطبیق داد.
هر وقت روی یه تایپِ جمع مثل Bool تطبیقِ case یا تطبیقِ الگو انجام میدیم، باید برای هر دادهساز تعریفِ جدا داشته باشیم، یا یه تعریفِ پیشفرض برای انطباق با همهی دادهسازها داشته باشیم. در واقع همیشه باید هر دو حالت رو در نظر بگیریم، یا از تابعی که هر دو حالت رو در نظر میگیره استفاده کنیم؛ در غیر اینصورت یه تابعِ ناقص نوشتیم که ممکنه خطای زمان اجرا بده. واقعاً به ندرت چنین کاری توجیه داره؛ پس توابعی بنویسین که همهی ورودیهای ممکن رو در نظر میگیرن!
با یه بیانیهی if-then-else که در فصلِ قبل دیدیم شروع میکنیم:
If x + 1 == 1 then "AWESOME" else "wut"میشه این رو با بیانیهی case، با انطباق روی دادهسازهای Bool بازنویسی کنیم:
funcZ x =
case x + 1 == 1 of
True -> "AWESOME"
False -> "wut"با اینکه گرامر خیلی تغییر کرده، ولی جواب هَمونه. حتماً تو REPL بارگذاری و امتحانش کنین.
میتونیم تابعی که واروخوانه بودنِ لغات رو تشخیص میده با بیانیهی case بنویسیم:
pal xs =
case xs == reverse xs of
True -> "yes"
False -> "no"این تابع رو با عبارتِ where هم میشه نوشت؛ برای وقتهایی که ممکنه بخواین باز هم از y استفاده کنین:
pal' xs =
case y of
True -> "yes"
False -> "no"
where y = xs == reverse xsدر هر دو صورت، اول تابعِ تساوی نوشته ِ ورودی رو با معکوس ِش چک میکنه. اگه True برگشت، پس نوشته ِ ورودی یه واروخوانه است و تابع میگه "yes". اگر هم نه، واروخوانه نیست.
یه مثال دیگه، این بار هم انطباق روی دادهسازهای Bool. یه نسخه با if-then-else از این مثال رو قبلاً دیدیم، میتونین گرامرهاشون رو مقایسه کنین:
-- greetIfCool3.hs
module GreetIfCool3 where
greetIfCool :: String -> IO ()
greetIfCool xs =
case cool of
True -> putStrLn "eyyyyy. What's shakin'?"
False -> putStrLn "pshhhh."
where cool = coolness == "downright frosty yo"تا اینجا هر بیانیهی case ای که دیدیم تطبیق الگوهای ساده و صریح با True و False بودن. در یکی بخشهای بعد، یه راه دیگه برای نوشتن بیانیهی case میبینیم.
تمرینها: ورزش case
نوشتن بیانیههای case رو با بازنویسیِ چند تابع تمرین میکنیم. بعضی از این توابع رو در فصلهای قبل دیدین (بعضیهاشون هم بعداً با گرامرهای دیگهای باز میبینین!)، ولی الان نسخهی جدیدشون رو مینویسین. همهی این تمرینها طوری نوشته شدن که انگار تو فایل منبع هستن، ما هم به شما همین رو پیشنهاد میکنیم، که بجای نوشتن اونها مستقیماً تو REPL، از فایل بارگذاریشون کنین.
اول بیانیههای if-then-else رو با بیانیههای case بازنویسی کنین.
۱.
این تابع باید وقتی x بزرگتر از y هست، x برگردونه.
functionC x y = if (x > y) then x else y۲.
این تابع به مقادیرِ زوج ۲ تا اضافه میکنه، و مابقیِ مقادیر رو دست نخورده برمیگردونه.
ifEvenAdd2 n = if even n then (n+2) else n۳.
تابع زیر مقادیرِ ورودی (x) رو با صفر مقایسه میکنه و بسته به مثبت یا منفی بودنشون یه خروجی میده. اگه ورودی صفر بود چطور؟ شاید لازم باشه یه کم با تابعِ compare بازی کنین تا بتونین این تابع رو تکمیل کنین.
nums x =
case compare x 0 of
LT -> -1
GT -> 1