۱۹ - ۵بعضی عملیات پایهای
تایپکلاسِ Foldable
شامل عملیاتهای دیگهای هم میشه که هنوز چیزی ازشون نگفتیم. بعضی از اونها مثلِ length
قبلاً فقط برای استفاده با لیستها تعریف شده بودن، اما الان تعمیم داده شدن تا با بقیهی انواعِ ساختارِ داده هم کاربرد داشته باشن. اینجا توصیف، تایپ سیگنچر، و مثالهایی از خیلی از این توابع رو نوشتیم:
-- | ،لیست المانهای یه ساختار
-- | .از چپ به راست
toList :: t a -> [a]
Prelude> toList (Just 1)
[1]
Prelude> let xs = [Just 1, Just 2, Just 3]
Prelude> map toList xs
[[1],[2],[3]]
Prelude> concatMap toList xs
[1,2,3]
Prelude> let xs = [Just 1, Just 2, Nothing]
Prelude> concatMap toList xs
[1,2]
Prelude> toList (1, 2)
[2]
چرا اون ۱ رو نذاشت تو لیست؟ به همون دلیل که fmap
یه تابع رو به اون ۱ اعمال نمیکنه.
-- | تست برای خالی بودنِ یه ساختار
null :: t a -> Bool
دقت کنین که null
با مقادیرِ Left
و Nothing
هم، مثل لیستِ خالی، True
برمیگردونه:
Prelude> null (Left 3)
True
Prelude> null []
True
Prelude> null Nothing
True
Prelude> null (1, 2)
False
Prelude> let xs = [Just 1, Just 2, Nothing]
Prelude> fmap null xs
[False,False,True]
تابع بعدی، length
، تعداد مقادیرِ a
که در t a
هستن رو برمیگردونه. یه لیست، به خاطرِ تعریفِش، ممکنه چندتا مقدار a
داشته باشه. دقت کنین برای توپلها، اولین آرگومان (و همینطور چپترین، یا بیرونیترین آرگومانهای تایپیِ نوعدادههایی مثل Maybe
و Either
) جزئی از t
به حساب میان، نه جزئی از a
.
-- | طول یا سایز یه ساختار متناهی
-- | .برمیگردونه Int رو به عنوان یه
length :: t a -> Int
Prelude> length (1, 2)
1
Prelude> let xs = [(1, 2), (3, 4), (5, 6)]
Prelude> length xs
3
Prelude> fmap length xs
[1,1,1]
Prelude> fmap length Just [1, 2, 3]
1
مثال آخر عجیبه، قبول داریم. اما اگه تو REPL اجراش کنین، همون جواب رو میگیرین. چرا؟ و چرا این:
Prelude> length $ Just [1, 2, 3]
1
همون جواب رو برمیگردونه؟
a
در اون مثال در Just a
یه لیسته. فقط هم یک لیست وجود داره.*
Prelude> let xs = [Just 1, Just 2, Just 3]
Prelude> fmap length xs
[1,1,1]
Prelude> let xs = [Just 1, Just 2, Nothing]
Prelude> fmap length xs
[1,1,0]
م. شاید این توضیح یه کم قانعکنندهتر باشه: در بیانیهی fmap length Just [1,2,3]
، به خاطر شرکتپذیری ِ چپ در اعمالِ توابع، میشه اینطور پرانتزگذاری کردِش: (fmap length Just) [1,2,3]
. جلوتر میبینیم که fmap
کردنِ یه تابع روی یه تابعِ دیگه، در واقع معادل با ترکیب ِ اون دو تابع هست. پس نهایتاً میرسیم به: (length . Just) [1,2,3]
که برابر است با: length $ Just [1,2,3]
.
-- | آیا المان در ساختار وجود داره؟
elem :: Eq a => a -> t a -> Bool
در مثالهای پایین از Either
استفاده کردیم تا رفتار تابعهای Foldable
رو با مقادیرِ Left
نشون بدیم. همونطور که با Functor
دیدیم، نمیشه از روی دادهساز ِ Left
نگاشت کرد، چون آرگومانِ تایپیِ سمت چپ جزئی از ساختار ِه. پس در مجموعه مثالهای پایین هم elem
نمیتونه داخلِ سازنده ِ Left
رو ببینه، در نتیجه حتی اگه مقداری که دنبالش هست توی Left
وجود داشته باشه، باز هم False
برمیگردونه:
Prelude> elem 2 (Just 3)
False
Prelude> elem True (Left False)
False
Prelude> elem True (Left True)
False
Prelude> elem True (Right False)
False
Prelude> elem True (Right True)
True
Prelude> let xs = [Right 1, Right 2, Right 3]
Prelude> fmap (elem 3) xs
[False,False,True]
-- | بزرگترین المانِ یه
-- | .ساختار غیرخالی
maximum :: Ord a => t a -> a
-- | کوچکترین المان یه
-- | .ساختار غیرخالی
minimum :: Ord a => t a -> a
دقت کنین که برای این توابع، مقادیرِ Left
و Nothing
(و مقادیرِ مشابه) خالی محسوب میشن.
Prelude> maximum [10, 12, 33, 5]
33
Prelude> let xs = [Just 2, Just 10, Just 4]
Prelude> fmap maximum xs
[2,10,4]
Prelude> fmap maximum (Just [3, 7, 10, 2])
Just 10
Prelude> minimum "julie"
'e'
Prelude> fmap minimum (Just "julie")
Just 'e'
Prelude> let xs = map Just "jul"
Prelude> xs
[Just 'j',Just 'u',Just 'l']
Prelude> fmap minimum xs
"jul"
Prelude> let xs = [Just 4, Just 3, Nothing]
Prelude> fmap minimum xs
[4,3,*** Exception: minimum: empty structure
Prelude> minimum (Left 3)
*** Exception: minimum: empty structure
توابعِ sum
و product
رو قبلاً دیدیم و از روی اسمشون هم میشه گفت چه کاری انجام میدن: جمع و ضرب ِ اعضای یه ساختار رو برمیگردونن:
sum :: (Foldable t, Num a) => t a -> a
product :: (Foldable t, Num a) => t a -> a
حالا چندتا مثال:
Prelude> sum (7, 5)
5
Prelude> fmap sum [(7, 5), (3, 4)]
[5,4]
Prelude> fmap sum (Just [1, 2, 3, 4, 5])
Just 15
Prelude> product Nothing
1
Prelude> fmap product (Just [])
Just 1
Prelude> fmap product (Right [1, 2, 3])
Right 6
تمرینها: تابعهای کتابخونه
توابع رو برمبنای foldMap
یا foldr
از Foldable
تعریف کنین، و بعد با چندتا تایپ که نمونه ِ Foldable
دارن امتحان کنین.
۱.
این و بعدی با foldMap
بهتر میشن، اما foldr
هم خوبه.
sum :: (Foldable t, Num a) => t a -> a
۲.
product :: (Foldable t, Num a) => t a -> a
۳.
elem :: (Foldable t, Eq a)
=> a -> t a -> Bool
۴.
minimum :: (Foldable t, Ord a)
=> t a -> Maybe a
۵.
maximum :: (Foldable t, Ord a)
=> t a -> Maybe a
۶.
null :: (Foldable t) => t a -> Bool
۷.
length :: (Foldable t) => t a -> Int
۸.
-- بعضیها این رو اصل قضیه
-- میدونن Foldable برای
toList :: (Foldable t) => t a -> [a]
۹.
-- .استفاده کنین foldMap راهنمایی: از
-- | المانهای یه ساختار رو با استفاده
-- | .از یه مانوید ترکیب کنین
fold :: (Foldable t, Monoid m) => t m -> m
۱۰.
-- .تعریف کنین foldr رو با foldMap
foldMap :: (Foldable t, Monoid m)
=> (a -> m) -> t a -> m