۲۴ - ۳دوتا فانکتور کوچولو رو درخت نشستن لیفت میکنن
کارمون رو با ترکیب ِ فانکتورها، به کمک تایپهایی که بالاتر دیدیم شروع میکنیم. میدونیم که میشه از رو Identity
لیفت کرد؛ این Functor
رو قبلاً دیدین:
instance Functor Identity where
fmap f (Identity a) = Identity (f a)
فانکتوری که برای Identity
هست در واقع هیچ کاری نمیکنه، فقط ماهیتِ Functor
رو نشون میده. تابع از روی بافت ِ Identity
لیفت میشه و بعد روی مقدارِ a
نگاشت میشه.
اگه از f
و g
نمونه ِ Functor
بخوایم، برای Compose
هم میشه یه نمونه ِ Functor
نوشت:
instance (Functor f, Functor g) =>
Functor (Compose f g) where
fmap f (Compose fga) =
Compose $ (fmap . fmap) f fga
حالا f
و g
هردوشون جزئی از ساختاری اند که از روش لیفت میکنیم، پس جفتشون هم باید Functor
باشن. برای اینکه بتونیم تابعی رو به مقداری که کاملاً داخلِ تایپ قرار گرفته اعمال کنیم، باید بتونیم از روی هردوتای اون لایهها بِپَریم. به خاطرِ وجودِ اون دو لایه، باید دوبار fmap
کنیم.
اگه برگردیم به مثالی که بالاتر داشتیم:
newtype Compose f g a =
Compose { getCompose :: f (g a) }
deriving (Eq, Show)
Compose { getCompose :: f (g a) }
Compose [] Maybe Int
و از نمونه ِ Functor
استفاده کنیم، میتونیم یه تابع رو به اون مقدارِ Int
که لای همهی اون ساختارها پوشونده شده اعمال کنیم:
Prelude> let xs = [Just 1, Nothing]
Prelude> Compose xs
Compose {getCompose = [Just 1,Nothing]}
Prelude> fmap (+1) (Compose xs)
Compose {getCompose = [Just 2,Nothing]}
این قضیه رو میشه به تعدادِ مختلفِ لایهها تعمیم داد، مثلِ زیر که یه لایه کمتر داره. این مثال شاید یادتون بیاد (از یکی از فصلهای قبل):
newtype One f a =
One (f a)
deriving (Eq, Show)
instance Functor f =>
Functor (One f) where
fmap f (One fa) = One $ fmap f fa
یا یه لایه ساختار بیشتر از Compose
:
newtype Three f g h a =
Three (f (g (h a)))
deriving (Eq, Show)
instance (Functor f, Functor g, Functor h)
=> Functor (Three f g h) where
fmap f (Three fgha) =
Compose $ (fmap . fmap . fmap) f fgha
مشابه تایپ ضرب ِ بینام (یعنی (,)
) و تایپ جمع ِ بینام (Either
)، تایپِ Compose
هم میشه به تعدادِ دلخواه تودرتو کرد:
v :: Compose []
Maybe
(Compose Maybe [] Integer)
v = Compose [Just (Compose $ Just [1])]
میشه اینطوری بهش فکر کرد که ترکیب ِ دو نوعدادهای که نمونه ِ Functor
دارن، باعث ایجادِ یه نمونه ِ Functor
ِ دیگه میشه. گاهی اوقات چنین چیزی رو اینطوری توصیف میکنن که فانکتورها تحتِ عملِ ترکیب بستهاند، یعنی وقتی دوتا Functor
رو با هم ترکیب میکنین، یه Functor
ِ دیگه میگیرین.