liftBase
является частью MonadBase
, которая является обобщением 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
Это легче увидеть, что практическое применение являются глядя на примеры. Например, bracket
из base
имеет подпись
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
С только MonadBase IO m
(или MonadIO m
), вы можете поднять главный bracket
вызов в m
но Брекетинг действия по-прежнему должны быть в простом старом IO
.
throw
и catch
, может быть, даже лучше примеры:
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
позволяет писать bracket
и catch
таким образом, что позволяет действия параметров также быть типа m a
вместо того, чтобы быть ограничена базовой монады. Общая реализация вышеуказанных функций (как и многих других) содержится в пакете 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
EDIT: И теперь, когда я на самом деле перечитайте ваш вопрос правильно ...
Нет, я не вижу никаких причин, почему подписи требует как MonadIO m
и MonadBaseControl IO m
поскольку MonadBaseControl IO m
должен означать MonadBase IO m
, который обеспечивает ту же функциональность. Так что, может быть, это просто что-то вроде старой версии.
Глядя на источник, это, вероятно, только потому, что runTCPClient
звонки sourceSocket
и sinkSocket
внутренне и те требуют MonadIO
. Я предполагаю, что причина, по которой все функции в пакете не просто используют MonadBase IO
, состоит в том, что MonadIO
более знаком людям, и большинство монад-трансформаторов имеют экземпляр, определенный для MonadIO m => MonadIO (SomeT m)
, но пользователям, возможно, придется написать свой собственный экземпляр для MonadBase IO
.
Спасибо, теперь это имеет смысл. Меня смутило то, что ['MonadBaseControl' в _conduit_] (http://hackage.haskell.org/package/conduit-1.0.9.3/docs/Data-Conduit.html#t:MonadBaseControl) отсутствует какое-либо определение, возможно, только имя импортируется/реэкспортируется там. –