۱۶ - ۱۳ساختار بیشتر، فانکتور بیشتر
گاهی پیش میاد که ساختار ِ یه تایپ، برای داشتنِ یه نمونه ِ Functor، احتیاج داشته باشه که یکی دیگه از لایههای میانیِ تایپهاش هم نمونه ِ Functor داشته باشه. چنین چیزی رو با نوعداده ِ زیر نشون میدیم:
data Wrap f a where
Wrap (f a)
deriving (Eq, Show)دقت کنین که a اینجا یه آرگومان برای f ِه. خوب چطور یه نمونه ِ Functor برای این بنویسیم؟
instance Functor (Wrap f) where
fmap f (Wrap fa) = Wrap (f fa)این کار نمیکنه، چون یه f اون وسط هست که از روش نمیپریم، و a (مقداری که fmap باید تابع رو بهش اعمال کنه) یه آرگومان برای اون f هست – تابع نمیتونه به اون f که a رو پوشونده اعمال بشه.
instance Functor (Wrap f) where
fmap f (Wrap fa) = Wrap (fmap f fa)اینجا تایپِ f رو نمیدونیم، و ممکنه هرچیزی باشه، ولی برای اینکه بشه از روش fmap کرد، حتماً باید تایپی باشه که یه نمونه ِ Functor داشته باشه. پس محدودیت رو اضافه میکنیم:
instance Functor f
=> Functor (Wrap f) where
fmap f (Wrap fa) = Wrap (fmap f fa)حالا اگه این نمونه ِ آخر رو بارگذاری کنیم، چنین نتیجههایی میده:
Prelude> fmap (+1) (Wrap (Just 1))
Wrap (Just 2)
Prelude> fmap (+1) (Wrap [1, 2, 3])
Wrap [2,3,4]باید برای هر Functor ای کار کنه. اگه یه چیزی که Functor نیست بهش بدیم چی؟
Prelude> let n = 1 :: Integer
Prelude> fmap (+1) (Wrap n)
Couldn't match expected type ‘f b’
with actual type ‘Integer’
Relevant bindings include
it :: Wrap f b (bound at <interactive>:8:1)
In the first argument of ‘Wrap’, namely ‘n’
In the second argument of ‘fmap’,
namely ‘(Wrap n)’اون عدد به تنهایی، ساختار ِ اضافیای که Wrap لازم داره تا به عنوانِ یه Functor عمل کنه رو ارائه نمیده. انتظار داره بتونه از روی یه f مستقل از a، fmap کنه، که چنین چیزی با هیچ ثابتِ تایپ ای مثلِ Integer ممکن نیست.