۱۷ - ۲تعریف اپلیکتیو
اولین چیزی که از تعریفِ این تایپکلاس متوجه میشین، اینه که اون f که ساختار رو نشون میده، مشابهِ Functor، خودش با تایپکلاسِ Functor محدود شده:
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f bپس هر تایپی که بخواد یه نمونه ِ Applicative داشته باشه، باید قبلش یه نمونه ِ Functor داشته باشه.
تابع ِ pure یه کارِ خیلی ساده انجام میده: یه چیز رو به داخلِ ساختار ِ فانکتوری (اپلیکتیو) لیفت میکنه. میشه این رو حداقلِ یه ساختار یا همانیِ ساختاری دونست. قوانین رو که بگیم، منظورمون رو از این همانی توضیح میدیم. عملیات ِ جالبترِ این تایپکلاس، <*> ِه. این یه تابعِ میانوند ِه به اسمِ اَپلای یا گاهی اوقات اَپ.
اگه تایپهای <*> و fmap رو با هم مقایسه کنیم، شباهتشون رو میبینیم:
-- fmap
(<$>) :: Functor f
=> (a -> b) -> f a -> f b
(<*>) :: Applicative f
=> f (a -> b) -> f a -> f bفرقشون اون f ِه که بیرونِ تابع در دومین تعریف قرار گرفته و ساختار ِ فانکتوری رو ارائه میده. یه ذره جلوتر مفهومِ این رو در عمل میبینیم.
در کنارِ این توابعِ اصلی (یا هستهای)، کتابخونه ِ Control.Applicative چندتا تابعِ بهدردبخورِ دیگه هم در اختیار میذاره: liftA، liftA2، و liftA3:
liftA :: Applicative f =>
(a -> b)
-> f a
-> f b
liftA2 :: Applicative f =>
(a -> b -> c)
-> f a
-> f b
-> f c
liftA3 :: Applicative f =>
(a -> b -> c -> d)
-> f a
-> f b
-> f c
-> f dاگه تایپِ liftA رو دیدین و پیشِ خودتون فکر کردین که این همون fmap ِه، حق با شماست. اساساً همون fmap ِه، با این تفاوت که بجای Functor، محدودیت تایپکلاسی ِ Applicative داره. از اونجا که همهی اپلیکتیوها فانکتور هم هستن، این تمایزِ خیلی مهمی نیست.
liftA2 و liftA3 هم بطورِ مشابه، همون fmap هستن که تابعهای با آرگومانهای بیشتر میگیرن. فهمیدنِ اینها بدونِ مثال خیلی آسون نیست، پس با چندتا مثال ادامه میدیم تا شروع کنیم به درکِ کاربردِ اپلیکتیوها.