۷ - ۵بیانیههای 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