۷ - ۱۱تمرینهای فصل
تستی
۱.
یک تابعِ پلیمورفیک
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 = x
a)
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` 10
a)
اول با 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)
جواب بده. فقط گرامر ِ تعیین تایپ (::
) و پرانتز (برای تعیین گستره) لازم دارین.