۲۱ - ۴فانکتورِ توابع
اگه تو REPL بزنین :info Functor، یکی از نمونههایی که میبینین برای نوعساز ِ نیمه اعمالشده ِ توابعه ((->) r):
instance Functor ((->) r)ممکنه یه ذره گیجکننده باشه، پس ما هم به امید اینکه بیشتر جا بیوفته بازِش میکنیم. اول ببینیم چه کارهایی میشه باهاش کرد:
Prelude> fmap (+1) (*2) 3
7
-- یه ذره جابجایی
Prelude> fmap (+1) (*2) $ 3
7
Prelude> (fmap (+1) (*2)) 3
7این باید براتون آشنا باشه:
Prelude> (+1) . (*2) $ 3
7
Prelude> (+2) . (*1) $ 2
4
Prelude> fmap (+2) (*1) $ 2
4
Prelude> (+2) `fmap` (*1) $ 2
4خوشبختانه اینجا چیزی عجیب نیست. اگه تعریفِ نمونه رو در base ببینین، اینطوریه:
instance Functor ((->) r) where
fmap = (.)اول تایپها رو باز کنیم. به خاطر داشته باشین که (->) دو آرگومان میگیره و در نتیجه کایندِش * -> * -> * است. پس از اول میدونیم که باید یکی از آرگومانها رو اعمال کنیم تا بشه یه Functor داشته باشیم. در Either Functor دیدیم که تابع از روی Either a لیفت میشد و اگه قرار به اعمال شدن بود، به b اعمال میشد. با تایپِ توابع:
data (->) a bهمون قاعده برقراره: باید از روی ((->) a) لیفت کرد تا فقط مقدارِ b تغییر کنه. یه جور رسمه که در این مواقع برای Reader، بجای a از r استفاده شه، ولی هر حرفِ دیگهای هم باشه کار میکنه. اینجا r اولین آرگومان برای (a -> b) ِه:
-- نوعساز توابع (type constructor of functions)
(->)
-- تماماً اعمالشده (fully applied)
a -> b
((->) r)
-- معادل است با
r ->
-- تایپ ِ آرگومان تابعه ،r پسبا این متوجه میشیم که r (تایپِ آرگومان برای توابع) بخشی از ساختاری ِه که یه تابع رو از روش لیفت میکنیم، نه مقداری که تابع روش نگاشت میشه (یا تغییر میکنه).
پس جوابِ تابع همون مقداری میشه که تغییر میکنه. اگه این رو با ترکیبِ توابع مقایسه کنیم، خیلی خوب با هم جور میشن:
(.) :: (b -> c) -> (a -> b) -> a -> c
-- یا شاید
(.) :: (b -> c) -> (a -> b) -> (a -> c)مقایسهش با Functor چطور میشه؟
(.) :: (b -> c) -> (a -> b) -> (a -> c)
fmap :: Functor f => (a -> b) -> f a -> f bاز اینجا به بعد دیگه اسمِ توابع و محدودیتهای تایپکلاسی رو حذف میکنیم چون بدیهیاند:
:: (b -> c) -> (a -> b) -> (a -> c)
:: (a -> b) -> f a -> f b
-- تغییر حروف بدون تغییر در مفهوم
:: (b -> c) -> (a -> b) -> (a -> c)
:: (b -> c) -> f b -> f c
-- f ~ ((->) a)
:: (b -> c)
-> (a -> b)
-> (a -> c)
:: (b -> c)
-> ((->) a) b
-> ((->) a) c
-- تغییر گرامر پیشوندی به میانوندی
:: (b -> c) -> (a -> b) -> (a -> c)
:: (b -> c) -> (a -> b) -> (a -> c)خانمها و آقایان، لیفتِ فانکتوری برای توابع!