۲۱ - ۵پس 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 ???