۷ - ۱۱تمرینهای فصل
تستی
۱.
یک تابعِ پلیمورفیک
a)
وقتی صدا زده میشه، همه چیز رو تبدیل به گوسفند میکنه
b)
چند آرگومان داره
c)
یک تایپِ معین داره
d)
بسته به ورودیش، ممکنه به مقادیر با تایپهای متنوعی مقرر بشه
۲.
دو تابع به اسمهای f و g به ترتیب با تایپهای Char -> String و String -> [String] رو در نظر بگیرین. تابع ترکیبی ِ g . f چه تایپی داره؟
a)
Char -> String
b)
Char -> [String]
c)
[[String]]
d)
Char -> String -> [String]
۳.
یک تابعِ f با تایپِ Ord a => a -> a -> Bool رو به یه مقدار عددی اعمال میکنیم. حالا تایپش چیه؟
a)
Ord a => a -> Bool
b)
Num -> Num -> Bool
c)
Ord a => a -> a -> Integer
d)
(Ord a, Num a) => a -> Bool
۴.
یک تابع با تایپِ (a -> b) -> c:
a)
نیاز به مقادیر با سه تایپِ مختلف داره
b)
یک تابع سطح بالا هست
c)
برای آرگومان اولش باید یه توپل بگیره
d)
پارامترهاش به ترتیبِ حروف الفبا اند
۵.
با تعریفِ زیر برای f، تایپِ f True چیه؟
f :: a -> a
f x = xa)
f True :: Bool
b)
f True :: String
c)
f True :: Bool -> Bool
d)
f True :: a
کُد بنویسیم
۱.
تابعِ زیر دهگانِ یه آرگومانِ Integral رو برمیگردونه.
tensDigit :: Integral a => a -> a
tensDigit x = d
where xLast = x `div` 10
d = xLast `mod` 10a)
اول با divMod بازنویسیش کنین.
b)
آیا تایپِ نسخهی divMod ِ این تابع با نسخهی اصلیش یکسانه؟
c)
حالا تغییرش بدین تا بجای دهگان، صدگان رو خروجی بده. میتونین اینطور شروع کنین (التبه شاید تنها راه نباشه):
hunsD x = d2
where d = undefined
...۲.
تابع با تایپِ a -> a -> Bool -> a رو یکبار با بیانیهی case و یکبار هم با گارد تعریف کنین.
foldBool :: a -> a -> Bool -> a
foldBool =
error
"Error: Need to implement foldBool!"۳.
تعریفِ تابع رو بنویسین. دقت کنین که آرگومانِ اول یه تابعِ دیگهست که میشه به مقادیر اعمال بشه. آرگومان دوم هم یه توپل ِه، که میشه ازش برای تطبیق الگو استفاده کرد:
g :: (a -> b) -> (a, c) -> (b, c)
g = undefined۴.
برای این تمرین، نوشتن نسخهی بینقطه برای کُدِ موجود رو آزمایش میکنین؛ که مستلزمِ کمی اطلاعات جدیده. پس توضیحات زیر رو به دقت بخونین.
تایپکلاسها بر مبنای تایپها خبر میشن. Read یه تایپکلاس مشابه Show هست، اما دوگان یا متضاد ِ اونه. در کل، تایپکلاسِ Read چیزِ خوبی نیست که ازش استفاده کنین، ولی این تمرین برای آموزشِ چیزی دربارهی تعامل بین تایپکلاسها و تایپها طراحی شده.
تایپِ تابعِ read از تایپکلاسِ Read از این قراره:
read :: Read a => String -> aمتوجه الگویی شدین؟
read :: Read a => String -> a
show :: Show a => a -> Stringکد زیر رو تو یه فایلِ منبع بنویسین. بعد در GHCi بارگذاری و اجراش کنین تا مطمئن بشین دلیل هر جواب رو درک کردین.
-- arith4.hs
module Arith4 where
-- id :: a -> a
-- id x = x
roundTrip :: (Show a, Read a) => a -> a
roundTrip a = read (show a)
main = do
print (roundTrip 4)
print (id 4)۵.
بعد نسخهی بینقطه از roundTrip رو بنویسین (نکته: منظور تعریفِ تابعست، و نه اعمال ِ اون در main).
۶.
برای این تمرین هم به استفاده از ماژول ِ Arith4 ادامه میدیم.
وقتی show رو به یه مقدار مثلِ (1 :: Int) اعمال میکنیم، تایپِ a ای که باید یه نمونه از تایپکلاسِ Show داشته باشه Int میشه، در نتیجه GHCi هم برای تبدیل عدد ۱ ِما به نوشته، از نمونه ِ Show که برای Int تعریف شده استفاده میکنه.
از طرف دیگه، read انتظارِ یک آرگومانِ String داره تا یه a برگردونه. اون String که آرگومانِ اولِ read هست، هیچ اطلاعاتی دربارهی تایپِ نتیجهی تابع نمیده. ولی تابعِ roundTrip (با تایپ سیگنچر ای که الان داره) تایپِ خروجیش رو میدونه، چون با ورودیش یکسانه. یعنی تایپی که ورودی به show هست باید خروجیِ read هم باشه.
کاری که شما باید انجام بدین اینه که تایپِ roundTrip در Arith4 رو به (Show a, Read b) => a -> b تغییر بدین. حالا چطور میشه به GHCi گفت که کدوم نمونه از Read رو برای String خبر کنه؟ کاری کنین که بیانیهی print (roundTrip 4) جواب بده. فقط گرامر ِ تعیین تایپ (::) و پرانتز (برای تعیین گستره) لازم دارین.