۲۵ - ۴ترانسفورمرِ Reader یا ReaderT
در برنامههایی که با هسکل نوشته میشن، ReaderT
یکی از پرکاربردترین ترانسفورمرهاست. خیلی شبیهِ Reader
ِه، فقط در خروجیِ تابع یه ساختار ِ اضافه ایجاد میشه:
newtype ReaderT r m a =
ReaderT { runReaderT :: r -> m a }
مقدارِ داخلِ ReaderT
یه تابعه. اولین آرگومانِ اون تابع، جزئی از ساختار ایه که باید از روش بایند کنیم.
این بار نمونهها رو براتون مینویسیم. پس اگه خودتون میخواین بنویسین، جلوتر رو نخونین!
instance (Functor m)
=> Functor (ReaderT r m) where
fmap f (ReaderT rma) =
ReaderT $ (fmap . fmap) f rma
instance (Applicative m)
=> Applicative (ReaderT r m) where
pure a = ReaderT (pure (pure a))
(ReaderT fmab) <*> (ReaderT rma) =
ReaderT $ (<*>) <$> fmab <*> rma
instance (Monad m)
=> Monad (ReaderT r m) where
return = pure
(>>=) :: ReaderT r m a
-> (a -> ReaderT r m b)
-> ReaderT r m b
(ReaderT rma) >>= f =
ReaderT $ \r -> do
-- [1]
a <- rma r
-- [3] [ 2 ]
runReaderT (f a) r
-- [5] [ 4 ] [6]
۱.
باز هم تایپِ مقدارِ داخلِ ReaderT
باید تابع باشه، پس با گذاشتنِ یه تابع بینام (با یک آرگومان، که برای راحتی، اسمِ متغیرش رو گذاشتیم r
) داخلِ یه دادهساز ِ ReaderT
، تایپها رو جور کردیم.
۲.
مقدارِ r -> m a
رو با تطبیق الگو از دادهساز ِ ReaderT
خارج کردیم و به متغیرِ rma
انقیاد دادیم. و حالا داریم به اون r
که در بدنه ِ لامبدای بینام انتظار داریم اعمالِش میکنیم.
۳.
نتیجهی حاصل از اعمال ِ r -> m a
به یه مقدار از تایپِ r
میشه m a
. برای اینکه بتونیم تابعِ a -> ReaderT r m b
رو اعمال کنیم، به یه مقدار با تایپِ a
احتیاج داریم. میتونیم با استفاده از (<-)
، a
رو از داخلِ ساختار ِ m
به بیرون بایند (<-)
کنیم. اون مقدار رو به اسمِ a
بایند کردیم تا تایپش رو راحتتر به خاطر داشته باشیم.
۴.
اعمالِ f
(که تایپِ a -> ReaderT r m b
داره) به مقدارِ a
، یه مقدار با تایپِ ReaderT r m b
نتیجه میده.
۵.
از داخل ساختار ِ ReaderT
، مقدارِ r -> m b
رو درمیاریم.
۶.
نهایتاً r -> m b
ِ حاصل رو به r
که در شروعِ لاندا داشتیم اعمال میکنیم (همون آرگومانی که Reader
انتزاعی میکنه). این تابع بینام باید m b
برگردونه، در غیرِ اینصورت تابعِ معتبری نمیشه. برای معتبر بودن باید تایپِش r -> m b
باشه.
این دفعه تمرین نمیدیم، حقتونه یه استراحتی بکنین.