我正在編寫一個作爲守護程序運行的程序。 要創建守護程序,用戶提供了一組 實現爲每個所需的類(它們中的一個是一個數據庫) 所有這些類都函數具有形式StateT s IO a
,的 類型簽名的 但s
爲不同的每班。在StateT中組合多個狀態
假設每個類遵循以下模式:
import Control.Monad (liftM)
import Control.Monad.State (StateT(..), get)
class Hammer h where
driveNail :: StateT h IO()
data ClawHammer = MkClawHammer Int -- the real implementation is more complex
instance Hammer ClawHammer where
driveNail = return() -- the real implementation is more complex
-- Plus additional classes for wrenches, screwdrivers, etc.
現在我可以定義表示由 用戶對每個「時隙」選擇的實現的記錄。
data MultiTool h = MultiTool {
hammer :: h
-- Plus additional fields for wrenches, screwdrivers, etc.
}
和守護程序做大部分工作在StateT (MultiTool h ...) IO()
單子。
現在,由於多工具包含錘子,我可以在任何需要錘子的情況下使用它 。換句話說,所述MultiTool
類型 可以實現任何其所包含的類,如果我寫這樣的代碼:
stateMap :: Monad m => (s -> t) -> (t -> s) -> StateT s m a -> StateT t m a
stateMap f g (StateT h) = StateT $ liftM (fmap f) . h . g
withHammer :: StateT h IO() -> StateT (MultiTool h) IO()
withHammer runProgram = do
t <- get
stateMap (\h -> t {hammer=h}) hammer runProgram
instance Hammer h => Hammer (MultiTool h) where
driveNail = withHammer driveNail
但是的實現withHammer
,withWrench
,withScrewdriver
等 基本相同。這將是很好能夠寫的東西 這樣的...
--withMember accessor runProgram = do
-- u <- get
-- stateMap (\h -> u {accessor=h}) accessor runProgram
-- instance Hammer h => Hammer (MultiTool h) where
-- driveNail = withMember hammer driveNail
當然不會編譯不過。
我懷疑我的解決方案太面向對象。 有沒有更好的方法? Monad變壓器,也許? 非常感謝您的任何建議。
順便說一句,我因爲在你的簡單化取得了快速編輯你的代碼省略ClawHammer'的'實施你製作的東西可能不是你的意思。 –