我想在hedis(redis lib)的基礎上編寫一個簡單的DSL。我們的目標是編寫類似的功能:在hedis上構建monad,haskell redis lib
iWantThis :: ByteString -> MyRedis()
iWantThis bs = do
load bs -- :: MyRedis() It fetches a BS from Redis and puts it as
-- the state in a state monad
bs <- get -- :: MyRedis (Maybe ByteString) Gets the current state
put $ doSomethingPure bs -- :: MyMonad() Updates the state
commit -- :: MyRedis() Write to redis
的基本思想是從Redis的獲取數據,把它放在一個狀態單子,做一些東西與狀態,然後把更新的狀態回Redis的。
顯然,它應該是原子的,所以load
和put
應該發生在同一個Redis事務中。 Hedis允許通過將電話Redis
打包爲RedisTx (Queued a)
。例如,我們有get :: ByteString -> RedisTx (Queued a)
。 Queued
是一個monad,然後在Queued a
上運行multiExec
,在同一個事務中執行Queued a
中的所有內容。於是,我就確定我MyRedis
這樣:
import qualified Database.Redis as R
newtype MyRedis a = MyRedis { runMyRedis :: StateT MyState R.RedisTx a } -- deriving MonadState, MyState...
的run
函數調用multiExec
所以我相信,只要我留在MyRedis
一切都發生在同一個事務。
run :: MyRedis (R.Queued a) -> MyState -> IO (R.TxResult a)
run m s = R.runRedis (undefined :: R.Connection) (R.multiExec r)
where r = evalStateT (runMyRedis m) s
而且,我可以定義爲commit
:
commit :: ByteString -> MyRedis (R.Queued R.Status)
commit bs = do
MyState new <- get
(MyRedis . lift) (R.set bs new)
而一個computation
會是什麼樣子:
computation :: MyRedis (R.Queued R.Status)
computation = do
load gid
MyState bs <- get
put $ MyState (reverse bs)
commit gid
where gid = "123"
但我無法弄清楚如何寫 「負荷」
load :: ByteString -> MyRedis()
load gid = undefined
實際上,我認爲不可能寫load
,因爲get
是ByteString -> RedisTx (Queued (Maybe ByteString))
類型,我沒有辦法在不執行它的情況下窺探Queued
monad。
問題:
是不是正確的,因爲HEDIS的get類型的,它沒有意義的定義與上述語義的
load
功能?是否可以更改
MyRedis
類型定義使其工作?Hedis沒有定義一個
RedisT
monad變壓器。如果這樣的變壓器存在,會有幫助嗎?Hedis定義(但不會導出到lib用戶)
MonadRedis
typeclass;會讓我的monad成爲類型類的幫助實例嗎?這是正確的做法嗎?我想:
- 摘要在Redis的(我可能有一天會切換到另一個DB)
- 限制提供給我的用戶Redis的功能(基本上只提升到
MyRedis
get
和set
) - 保證,當我運行我的單子都在相同的(Redis的)發生交易
- 把我Redis的抽象在同級別其它功能在我的單子
你可以玩http://pastebin.com/MRqMCr9Q的代碼。對不起pastebin,目前lpaste.net已經關閉。
「我沒有辦法窺探排隊的monad而不執行它。」真?那麼'>> = :: Queued a - >(a - > Queued b) - > Queued?你已經給了'計算:: MyRedis(R.Queued R.Status)' - 非常明智的類型。但'load'應該是'load :: ByteString - > MyRedis(Queued())'。瀏覽圖書館文檔,似乎「排隊」和「RedisTx」在某種程度上是內在聯繫在一起的..我不明白爲什麼RedixTx每個人都能夠在沒有排隊的情況下出現(在多態函數中,當然,但這些只會是用Queued實例化) – user2407038
另外,這個問題非常非常廣泛。這顯然是一個問題!特別是「這是正確的做法嗎?」 - 這幾乎不可能回答。如何量化「正確」方法是什麼?實際上,我認爲,大多數事情都不是「正確的」 - 只是「足夠好」。你幾乎可以肯定地完成你陳述的目標,真正的問題是,redis的設計決策(和Haskell綁定它的)會幫助還是阻礙你?但這自然是一個非常難以回答的先驗問題...... – user2407038
「我沒有辦法窺視排隊的monad而不執行它。」 Redis庫以這種方式設計的原因是爲了防止以後的'RedisTx'行動取決於早期的結果。在你處理事務時,早先的命令還沒有運行。你想要什麼都做不到。現在,如果是我,我可能會試圖通過暴露批處理命令的'Applicative'接口來使這一點更加明顯,但我希望lib的作者有一個很好的理由這樣做。 –