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