۱۷ - ۳فانکتور و اپلیکتیو
قبلاً گفتیم که اپلیکتیوها، فانکتورهای مانویدی اند. پس چیزهایی که از Monoid و Functor یاد گرفتیم به یادگیریِ Applicative هم ربط دارن. یه کم این رابطه رو توضیح دادیم، ولی میخوایم درکِ عمیقتری پیدا کنیم.
اول تفاوتِ بین fmap و <*> رو دوره کنیم:
fmap :: (a -> b) -> f a -> f b
(<*>) :: f (a -> b) -> f a -> f bاون f پشتِ تابعِ (a -> b)، تنها فرقِ بین این دوتاست؛ ولی قدرتی که اضافه میکنه خیلی زیاده. یه دلیلش اینه که هر Applicative، یه نمونه ِ Functor هم داره؛ نه فقط بر مبنای تعریف – یه Functor رو میشه بر مبنای نمونه ِ Applicative تعریف کرد. از این کتاب خارج ِه، اما از قانونهای Functor و Applicative نتیجه میشه (قوانینِ Applicative رو تو همین فصل میگیم):
fmap f x = pure f <*> xاگه بخوایم این رو تو REPL ببینیم، باید اول Control.Applicative رو وارد کنیم (البته اگه از GHC ۷٫۸ یا قدیمیتر استفاده میکنین):
Prelude> fmap (+1) [1, 2, 3]
[2,3,4]
Prelude> pure (+1) <*> [1..3]
[2,3,4]با توجه به تایپِ pure که معادلِ Applicative f => a -> f a هست، میشه این تابع رو به چشمِ راهی برای قرار دادن ِ یه مقدار (با هر تایپی) به داخلِ ساختاری که باهاش سروکار داریم ببینیم:
Prelude> pure 1 :: [Int]
[1]
Prelude> pure 1 :: Maybe Int
Just 1
Prelude> pure 1 :: Eihter a Int
Right 1
Prelude> pure 1 :: ([a], Int)
([],1)با تایپِ سمت چپ در دو مثالِ آخر، یه طور دیگه رفتار شد. دلیلش هم مشابهِ مثال زیره:
Prelude> fmap (+1) (4, 5)
(4,6)تایپِ سمت چپ بخشی از ساختار ِه، و اعمال ِ تابع تغییری روی اون ساختار نمیده.