Это вопрос, связанный с практикой проектирования API для определения ваших собственных экземпляров Monad для библиотек Haskell. Определение экземпляров Monad кажется хорошим способом изолировать DSL, например. Par монада в monad-par, hdph; Process в распределенном процессе; Eval параллельно и т.д.
Я беру два примера библиотек haskell, целью которых является IO с базами данных. Примеры, которые я принимаю, riak для Riak IO и hedis для Redis IO.
В hedis определена a Redis monad . Оттуда вы запускаете IO с redis как:
data Redis a -- instance Monad Redis
runRedis :: Connection -> Redis a -> IO a
class Monad m => MonadRedis m
class MonadRedis m => RedisCtx m f | m -> f
set :: RedisCtx m f => ByteString -> ByteString -> m (f Status)
example = do
conn <- connect defaultConnectInfo
runRedis conn $ do
set "hello" "world"
world <- get "hello"
liftIO $ print world
В riak все по-другому:
create :: Client -> Int -> NominalDiffTime -> Int -> IO Pool
ping :: Connection -> IO ()
withConnection :: Pool -> (Connection -> IO a) -> IO a
example = do
conn <- connect defaultClient
ping conn
В документации для runRedis говорится: "Каждый вызов runRedis принимает сетевое соединение из пула соединений и запускает заданное действие Redis. Таким образом, вызовы runRedis могут блокироваться, пока все соединения из пула используются". Однако пакет riak также реализует пулы соединений. Это делается без дополнительных экземпляров монады поверх монады IO:
create :: Client-> Int -> NominalDiffTime -> Int -> IO Pool
withConnection :: Pool -> (Connection -> IO a) -> IO a
exampleWithPool = do
pool <- create defaultClient 1 0.5 1
withConnection pool $ \conn -> ping conn
Итак, аналогия между двумя пакетами сводится к двум следующим функциям:
runRedis :: Connection -> Redis a -> IO a
withConnection :: Pool -> (Connection -> IO a) -> IO a
Насколько я могу судить, пакет hedis представляет монаду Redis для инкапсуляции операций ввода-вывода с помощью redis с помощью runRedis. Напротив, пакет riak в withConnection просто принимает функцию, которая принимает Connection, и выполняет ее в монаде IO.
Итак, каковы мотивы для определения ваших собственных экземпляров Monad и стеков Monad? Почему пакеты riak и redis отличались своим подходом к этому?