۲۱ - ۵پس Reader کو؟

بله بله، البته. ‏‎Reader‎‏ یه ‏‎newtype‎‏ برای تایپِ تابع‌ه:

newtype Reader r a =
  Reader { runReader :: r -> a }

‏‎r‎‏ تایپی‌ه که می‌خونیم، و ‏‎a‎‏ تایپِ جوابِ تابع‌مونه.

نیوتایپ ِ ‏‎Reader‎‏ یه دستگیره* ِ خیلی خوب به اسمِ ‏‎runReader‎‏ داره که باهاش میشه تابع رو از ‏‎Reader‎‏ بیرون کشید. ببینیم میشه ثابت کنیم این همون تابع‌ه که یه کم جادوجمبلِ داده‌سازی بهش اضافه شده یا نه. ‏‎Functor‎‏ ِ این در مقایسه با ترکیبِ توابع چه شکلی میشه؟

instance Functor (Reader r) where
  fmap :: (a -> b)
       -> Reader r a
       -> Reader r b
  fmap f (Reader ra) =
    Reader $ \r -> f (ra r)

-- (.) همون
compose :: (b -> c) -> (a -> b) -> (a -> c)
compose f g = \x -> f (g x)

-- می‌بینین؟
\r -> f (ra r)
\x -> f (g  x)
*

م. یا اسمِ فیلد.

اساساً یکی‌اند دیگه، درسته؟ در فانکتور ِ ‏‎Reader‎‏، ‏‎ra‎‏ تایپِ‌ش ‏‎(r -> a)‎‏ ِه، و ‏‎f‎‏ هم تایپ‌ش ‏‎(a -> b)‎‏ ِه. اعمال ِ ‏‎ra‎‏ به مقدارِ ‏‎r‎‏ یه مقدار با تایپِ ‏‎a‎‏ میده، که بعد ‏‎f‎‏ بهش اعمال میشه و یه مقدار با تایپِ ‏‎b‎‏ میده. ترکیب توابع!

اگه خودمون رو نزنیم به اون راه که نمی‌دونیم این همون ترکیب توابع ِه، این نمونه ِ ‏‎Reader‎‏ رو یه جور دیگه هم میشه نوشت:

instance Functor (Reader r) where
  fmap :: (a -> b)
       -> Reader r a
       -> Reader r b
  fmap f (Reader ra) =
    Reader $ (f . ra)

اینجا این کارها رو می‌کنیم:

۱.

‏‎(r -> a)‎‏ رو از ‏‎Reader‎‏ میاریم بیرون.

۲.

‏‎f‎‏ رو با تابعی که از ‏‎Reader‎‏ باز کردیم ترکیب می‌کنیم.

۳.

تابعِ جدید حاصل از ترکیب رو دوباره میذاریم تو ‏‎Reader‎‏.

بدونِ نیوتایپ ِ ‏‎Reader‎‏، با حذفِ مراحل ۱ و ۳ به ترکیبِ توابع میرسیم.

بپرس

تابعِ زیر رو تعریف کنین. اگه گیر کردین، یادتون باشه که ساده‌تر از اونیه که به نظر میرسه. چیزی که می‌دونین رو بنویسین. از تایپِ ‏‎a‎‏ چی می‌دونین؟ اون تایپ به چی ساده میشه؟ اون تایپ چندتا سَکَنه داره؟ این تایپ رو قبلاً دیدین.

ask :: Reader a a
ask = Reader ???