2014-01-05 77 views
10

功能runTCPClient網絡導管具有以下特徵:「MonadIO m」和「MonadBaseControl IO m」是否有區別?

runTCPClient :: (MonadIO m, MonadBaseControl IO m) 
      => ClientSettings m -> Application m -> m() 

MonadIO m提供

liftIO :: IO a -> m a 

MonadBaseControl IO m提供

liftBase :: IO a -> m a 

沒有可見的差別。他們是否提供相同的功能?如果是,爲什麼類型簽名中的重複?如果不是,有什麼區別?

回答

12

liftBaseMonadBase它是MonadIO爲任何鹼單子的概括部分和,如你所說,MonadBase IO提供相同的功能MonadIO

然而,MonadBaseControl是一個更復雜的野獸。在MonadBaseControl IO m你有

liftBaseWith :: ((forall a. m a -> IO (StM m a)) -> IO a) -> m a 
restoreM  :: StM m a -> m a 

這是最簡單的,看看有什麼實際用途是通過看實例。例如,從basebracket具有簽名

bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c 

只需MonadBase IO m(或MonadIO m)可以解除主bracket調用到m但包圍行動,還需要在普通的舊IO

throwcatch的甚至更好的例子:

throw :: Exception e => e -> a 
catch :: Exception e => IO a -> (e -> IO a) -> IO a 

您可以輕鬆地從任何MonadIO m拋出一個異常,你可以從IO a趕上異常中MonadIO m但同樣,無論是在catch和正在運行的操作異常處理程序本身需要爲IO a而不是m a

現在MonadBaseControl IO使得有可能的方式,允許參數行動也有m a型的,而不是被限制到基單子寫bracketcatch。上述功能(以及其他功能)的通用實現可以在包lifted-base中找到。例如:

catch :: (MonadBaseControl IO m, Exception e) => m a -> (e -> m a) -> m a 
bracket :: MonadBaseControl IO m => m a -> (a -> m b) -> (a -> m c) -> m c 

編輯:現在,我居然重讀你的問題正確...

不,我看不出有任何理由簽名既需要MonadIO mMonadBaseControl IO mMonadBaseControl IO m應暗示MonadBase IO m,它啓用完全相同的功能。所以也許這只是一些舊版本的遺留問題。

看着來源,這可能是因爲runTCPClient在內部調用sourceSocketsinkSocket而那些需要MonadIO。我猜測爲什麼軟件包中的所有功能不是簡單地使用MonadBase IO的原因是人們更熟悉MonadIO,大多數單子變換器都有一個爲MonadIO m => MonadIO (SomeT m)定義的實例,但用戶可能必須編寫自己的實例MonadBase IO

+0

謝謝,現在它是有道理的。令我困惑的是[_conduit_中的'MonadBaseControl'](http://hackage.haskell.org/package/conduit-1.0.9.3/docs/Data-Conduit.html#t:MonadBaseControl)缺少任何定義,可能只有名稱在那裏被導入/重新導出。 –

相關問題