۱۹ - ۵بعضی عملیات پایهای
تایپکلاسِ 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 -> IntPrelude> 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