۱۷ - ۲تعریف اپلیکتیو

اولین چیزی که از تعریفِ این تایپکلاس متوجه میشین، اینه که اون ‏‎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‎‏ هستن که تابع‌های با آرگومان‌های بیشتر می‌گیرن. فهمیدنِ اینها بدونِ مثال خیلی آسون نیست، پس با چندتا مثال ادامه میدیم تا شروع کنیم به درکِ کاربردِ اپلیکتیو‌ها.