Это вопрос, связанный с практикой проектирования 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 отличались своим подходом к этому?