۲۵ - ۱۰تایپکلاسِ MonadIO، یا همون زوم-زوم
راههای زیادی برای لیفت ِ یه اجراییه از روی ساختار ِ اضافه وجود داره. MonadIO طراحیِ متفاوتی نسبت به MonadTrans داره، چون بجای اینکه لایه به لایه لیفت کنه، MonadIO یه اجراییه ِ IO رو انقدر لیفت میکنه تا از روی همهی ساختارهای پوشوندهشده داخلِ بیرونیترین IO لیفت کرده باشه. هدف اینه که یه بار بنویسین liftIO و خودش با همهی تایپهای زیر کار کنه:
liftIO :: IO a -> ExceptT e IO a
liftIO :: IO a -> ReaderT r IO a
liftIO :: IO a -> StateT s IO a
liftIO :: IO a -> StateT s (ReaderT r IO) a
liftIO :: IO a
-> ExceptT
e
(StateT s (ReaderT r IO))
aاگه Monad ِ پایه (بیرونیترین) IO باشه، برای رسیدن بهش لازم نیست چندبار لیفت کنین، چون liftIO دارین.
در کتابخونه ِ transformers کلاس MonadIO در ماژول ِ Control.Monad.IO.Class قرار گرفته:
class (Monad m) => MonadIO m where
-- | یک محاسبه رو از
-- | لیفت کن. IO موندِ
liftIO :: IO a -> m aاین توضیح توی ماژول، نسبتاً خوبه، اما نقطهی تمایزِ MonadIO از MonadTrans رو پررنگ نکرده:
موندهایی که ممکنه محاسباتِ IO درونشون پوشونده بشن. هر موندی که از اعمال ِ یه تسلسل از موند ترانسفورمرها به موند ِ IO درست شده باشه، یه نمونه از این کلاس میشه.
نمونهها باید قانونهای زیر رو (که میگن liftIO یه ترانسفورمر از موندهاست) ارضا کنن:
۱.
liftIO . return = return۲.
liftIO (m >>= f) =
liftIO m >>= (liftIO . f)مثالِ scotty رو تغییر میدیم تا یه نوشته چاپ کنه:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Web.Scotty
import Control.Monad.IO.Class
import Data.Monoid (mconcat)
main = scotty 3000 $ do
get "/:word" $ do
beam <- param "word"
liftIO (putStrLn "hello")
html $
mconcat ["<h1>Scotty, ",
beam,
" me up!</h1>"]حالا اگه main رو تو REPL اجرا کنین یا یه باینری بسازین و اجرا کنین، میتونین از طریق مرورگرِتون، از سروِر درخواستِ پاسخ کنین (همونطور که قبلاً نشون دادیم). این کار رو از طریق یه برنامهی تحتِ command line مثلِ curl هم میتونین انجام بدین. اگه از مرورگر استفاده کردین و hello چند بار چاپ شده، به احتمالِ قوی مرورگرِتون بیشتر از یک بار درخواست داده. اگه با curl امتحان کنین، نباید چنین رفتاری ببینین.
مثال از نمونههای MonadIO
۱.
IdentityT
instance (MonadIO m)
=> MonadIO (IdentityT m) where
liftIO = IdentityT . liftIO۲.
EitherT
instance (MonadIO m)
=> MonadIO (EitherT e m) where
liftIO = lift . liftIOتمرینها: چندتا نمونه
۱.
MaybeT
instance (MonadIO m)
=> MonadIO (MaybeT m) where
liftIO = undefined۲.
ReaderT
instance (MonadIO m)
=> MonadIO (ReaderT r m) where
liftIO = undefined۳.
StateT
instance (MonadIO m)
=> MonadIO (StateT s m) where
liftIO = undefinedراهنمایی: نمونههاتون باید ساده باشن.