۲۵ - ۱۰تایپکلاسِ 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
راهنمایی: نمونههاتون باید ساده باشن.