۱۰ - ۱۰تمرین‌های فصل

نرمش و دوره

برای این تمرین‌ها انتظار نمیره از فولد استفاده کنین. اینها رو برای دوره‌ی مطالبی که در فصل‌های قبل خوندیم آوردیم. با هر راهی که تا اینجا یاد گرفتین حل کنین.

۱.

با حروفِ بی‌صدا و صدادارِ زیر:

stops = "pbtdkg"
vowels = "aeiou"

a)

تابعی بنویسین که ‏‎stops‎‏ و ‏‎vowels‎‏ رو به عنوان ورودی بگیره، و همه‌ی توپل‌‌های سه‌تاییِ ممکن با ترکیبِ ساکن-صدادار-ساکن رو برگردونه. همه‌ی توپل‌‌ها یه لغت انگلیسی نمیشن، ولی این ساکن-صدادار-ساکن انقدر رایجه که خیلی‌هاشون یه لغاتِ معنی‌داری میشن.

b)

تابع بالا رو تغییر بدین تا فقط توپل‌‌هایی رو بده که با p شروع میشن.

c)

حالا بجای لیستِ حروف ساکن و صدادار، لیست‌هایی از اسم و فعل تعریف کنین، و کاری کنین تابع‌تون توپل‌‌های اسم-فعل-اسم برگردونه.

۲.

تابعِ رمزآلود زیر چی کار می‌کنه؟ تایپ‌ش چیه؟ سعی کنین قبل از تست کردن تو REPL، مطمئن بشین چه کاری انجام میده.

seekretFunc x =
  div (sum (map length (words x)))
      (length (words x))

۳.

جواب دقیق‌تر می‌خوایم... می‌تونین تابعِ بالا رو با تقسیمِ کسری بازنویسی کنین؟

بازنویسی توابع با فولد

در فصلِ قبل این توابع رو با خوداتکایی روی لیست نوشتین. حالا برای این تمرین با فولد بازنویسی‌شون کنین. برای درک بهتر فولدها، هرجا میشد، نسخه‌ی فولددار رو بی‌نقطه بازنویسی کنین.

نسخه‌ی بی‌نقطه ِ این توابع که با فولد تعریف شدن، شبیهِ این میشه:

myFunc = foldr f z

برای مثال، تابعِ ‏‎and‎‏:

-- باز هم با این تایپ کاربردشون
-- محدودتر از نسخه‌ی معادل‌شون در
-- .یا جدیدتر میشه. مهم نیست GHC 7.10

-- (&&) مستقیم، بدون recursion
myAnd :: [Bool] -> Bool
myAnd [] = True
myAnd (x:xs) =
  if x == False
  then False
  else myAnd xs

-- (&&) مستقیم، با استفاده از recursion
myAnd :: [Bool] -> Bool
myAnd [] = True
myAnd (x:xs) = x && myAnd xs

-- تعریف با فولد،
-- تابع فولدینگ بی‌نقطه نیست
myAnd :: [Bool] -> Bool
myAnd = foldr
        (\a b ->
          if a == False
          then False
          else b) True

-- myAnd تعریف با فولد، حالا هم
-- و هم تابع فولدینگ بی‌نقطه‌اند
myAnd :: [Bool] -> Bool
myAnd = foldr (&&) True

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

۱.

تابعِ ‏‎myOr‎‏ اگه حداقل یک مقدارِ ‏‎Bool‎‏ در لیستِ ورودی ‏‎True‎‏ باشه، باید ‏‎True‎‏ برگردونه.

myOr :: [Bool] -> Bool
myOr = undefined

۲.

تابعِ ‏‎‎‏myAny در صورتی ‏‎True‎‏ بر می‌گردونه که از اعمال ِ ‏‎a -> Bool‎‏ به حداقل یکی از المان‌های لیست، جوابِ ‏‎True‎‏ بدست بیاد.

myAny :: (a -> Bool) -> [a] -> Bool
myAny = undefined

چندتا مثال برای تست کردنِ ‏‎myAny‎‏:

Prelude> myAny even [1, 3, 5]
False
Prelude> myAny odd [1, 3, 5]
True

۳.

دو نسخه از تابعِ ‏‎myElem‎‏ تعریف کنین: یکی با فولد کار کنه، و اون یکی با ‏‎any‎‏.

myElem :: Eq a => a -> [a] -> Bool 
Prelude> myElem 1 [1..10]
True
Prelude> myElem 1 [2..10]
False

۴.

تابعِ ‏‎myReverse‎‏ رو تعریف کنین. نگرانِ تنبل کردنِ‌ش نباشین.

myReverse :: [a] -> [a]
myReverse = undefined
Prelude> myReverse "blah"
"halb"
Prelude> myReverse [1..5]
[5,4,3,2,1]

۵.

تابعِ ‏‎myMap‎‏ رو با ‏‎foldr‎‏ تعریف کنین. باید مثلِ خودِ ‏‎map‎‏ عمل کنه.

myMap :: (a -> b) -> [a] -> [b]
myMap = undefined

۶.

تابعِ ‏‎myFilter‎‏ رو با ‏‎foldr‎‏ تعریف کنین. باید مثل خود ‏‎filter‎‏ عمل کنه.

myFilter :: (a -> Bool) -> [a] -> [a]
myFilter = undefined

۷.

تابعِ ‏‎‎‏squish یه لیستِ لیست رو به یک لیست تبدیل می‌کنه.

squish :: [[a]] -> [a]
squish = undefined

۸.

تابعِ ‏‎squishMap‎‏ یه تابع رو به یک لیست نگاشت میده و نتیجه‌هاشون رو الحاق می‌کنه.

squishMap :: (a -> [b]) -> [a] -> [b]
squishMap = undefined
λ> squishMap (\x -> [1, x, 3]) [2]
λ> [1,2,3]
λ> squishMap (\x -> "WO "++[x]++" OT ") "blah"
"WO b OT WO l OT WO a OT WO h OT "

۹.

تابعِ ‏‎squishAgain‎‏ یه لیستِ لیست رو به یک لیست لِه می‌کنه. این بار از تابعِ ‏‎‎‏squishMap استفاده کنین.

squishAgain :: [[a]] -> [a]
squishAgain = undefined

۱۰.

تابعِ ‏‎myMaximumBy‎‏ یک تابعِ مقایسه و یک لیست می‌گیره، و بر مبنای آخرین مقداری که از مقایسه خروجیِ ‏‎GT‎‏ میده، بزرگترین المانِ لیست رو برمی‌گردونه.

myMaximumBy :: (a -> a -> Ordering)
            -> [a]
            -> a
myMaximumBy = undefined
Prelude> myMaximumBy (\_ _ -> GT) [1..10]
1
Prelude> myMaximumBy (_ _ -> LT) [1..10]
10
Prelude> myMaximumBy compare [1..10]
10

۱۱.

تابعِ ‏‎myMinimumBy‎‏ یک تابع مقایسه و یک لیست می‌گیره، و بر مبنای آخرین مقداری که از مقایسه خروجیِ ‏‎LT‎‏ میده، کوچکترین المانِ لیست رو برمی‌گردونه.

myMinimumBy :: (a -> a -> Ordering)
            -> [a]
            -> a
myMinimumBy = undefined
Prelude> myMinimumBy (\_ _ -> GT) [1..10]
10
Prelude> myMinimumBy (_ _ -> LT) [1..10]
1
Prelude> myMinimumBy compare [1..10]
1