Đây là câu hỏi liên quan đến thực tiễn thiết kế API để xác định các cá thể Monad của riêng bạn cho các thư viện Haskell. Xác định các trường hợp Monad có vẻ là một cách tốt để tách biệt DSL, ví dụ: Par
đơn nguyên trong đơn nguyên, hdph; Process
trong quá trình phân phối; Eval
song song, v.v ...Khi nào (và khi nào không) để xác định Monad
Tôi lấy hai ví dụ về thư viện haskell, mục đích của nó là IO với phần phụ trợ cơ sở dữ liệu. Các ví dụ tôi lấy là riak cho Riak IO và hedis cho Redis IO.
Trong hedis, Redis
đơn nguyên is defined. Từ đó, bạn chạy IO với redis như:
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
Trong riak, mọi thứ đều khác nhau:
create :: Client -> Int -> NominalDiffTime -> Int -> IO Pool
ping :: Connection -> IO()
withConnection :: Pool -> (Connection -> IO a) -> IO a
example = do
conn <- connect defaultClient
ping conn
Các tài liệu cho runRedis
nói: "Mỗi cuộc gọi của runRedis mất kết nối mạng từ Connection và chạy hành động Redis đã cho. Lệnh gọi runRedis có thể chặn trong khi tất cả các kết nối từ nhóm đang được sử dụng. ". Tuy nhiên, gói riak cũng thực hiện các pool kết nối. Này được thực hiện mà không trường hợp đơn nguyên thêm trên đầu trang của các đơn nguyên 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
Vì vậy, sự tương tự giữa hai gói nắm để hai chức năng:
runRedis :: Connection -> Redis a -> IO a
withConnection :: Pool -> (Connection -> IO a) -> IO a
Theo như tôi có thể nói, gói hedis giới thiệu một đơn nguyên Redis
để đóng gói các hành động IO với redis bằng cách sử dụng runRedis
. Ngược lại, gói riak trong withConnection
chỉ đơn giản là lấy một hàm mất Connection
và thực hiện nó trong đơn nguyên IO.
Vì vậy, động lực để xác định các trường hợp Monad của riêng bạn và ngăn xếp Monad là gì? Tại sao gói riak và redis lại khác với cách tiếp cận này?
Như một ngữ cảnh cho câu trả lời - trong trường hợp không rõ ràng, các loại 'Redis a' và' Connection -> IO a' tương đương nhau. Vì vậy, đây thực chất là một sự khác biệt về mỹ phẩm, có thể so sánh với 'env -> IO a' so với' ReaderT env IO a'. –
Điều đó có nghĩa là có lẽ không chính xác và 'Kết nối IO mã hóa 'là đơn nguyên mà anh muốn tất cả cùng. –