14

これは、Haskell ライブラリ用に独自の Monad インスタンスを定義するための API 設計手法に関する質問です。ParMonad インスタンスを定義することは、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 パッケージで、これに対するアプローチが異なるのはなぜですか?

4

2 に答える 2