これは、Haskell ライブラリ用に独自の Monad インスタンスを定義するための API 設計手法に関する質問です。Par
Monad インスタンスを定義することは、DSL のモナド (monad-par、hdph など)を分離するための良い方法のようです。Process
分散プロセスで; Eval
並行して…など
Haskell ライブラリの 2 つの例を取り上げます。その目的は、データベース バックエンドとの IO です。私が取る例は、Riak IO のriakと Redis IO のhedisです。
hedis では、Redis
モナドが定義されています。そこから、次のように redis で IO を実行します。
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
は次のように書かれています。. ただし、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
したがって、2 つのパッケージの類似点は、次の 2 つの機能に集約されます。
runRedis :: Connection -> Redis a -> IO a
withConnection :: Pool -> (Connection -> IO a) -> IO a
私が知る限り、hedis パッケージはRedis
を使用して redis で IO アクションをカプセル化するモナドを導入しrunRedis
ます。対照的に、 の riak パッケージはwithConnection
単に , を取る関数を取り、Connection
それを IO モナドで実行します。
では、独自の Monad インスタンスと Monad スタックを定義する動機は何ですか? riak と redis パッケージで、これに対するアプローチが異なるのはなぜですか?