我想定義一個狀態monad來管理錯誤(從某種意義上來說可能是這樣):如果在「do」計算過程中出現錯誤/問題,它將由>>=
引導並傳播。 該錯誤還應包含描述它的字符串。 之後,我想將這個monad應用到mapTreeM
,使用map來表示一個函數,該函數假設狀態爲數字和包含數字的樹,並且在每個訪問步驟中通過將當前葉的值添加到當前狀態來更新當前狀態;生成的樹必須包含一個具有舊葉值和訪問時刻狀態的對。如果在計算過程中狀態變爲負值,那麼這種訪問就會失敗,如果變爲正值,就會成功。如何定義狀態monad?
例如鑑於此樹:Branch (Branch (Leaf 7) (Branch (Leaf (-1)) (Leaf 3))) (Branch (Leaf (-2)) (Leaf 9))
我們得到一棵樹(考慮初始狀態0):Branch (Branch (Leaf (7,7)) (Branch (Leaf (-1,6)) (Leaf (3,9)))) (Branch (Leaf (-2,7)) (Leaf (9,16)))
如果我們在第二葉放-18
,我們應該得到我們達到了一個負面狀態(-11)
錯誤值的信號。
我做了這樣的事情來打印樹沒有管理錯誤...我還沒有明白如何去做。 以下是我的代碼:
module Main where
-- State monad
newtype State st a = State (st -> (st, a))
instance Monad (State state) where
return x = State(\s -> (s,x))
State f >>= g = State(\oldstate ->
let (newstate, val) = f oldstate
State newf = g val
in newf newstate)
-- Recursive data structure for representing trees
data Tree a = Leaf a | Branch (Tree a) (Tree a)
deriving (Show,Eq)
-- Utility methods
getState :: State state state
getState = State(\state -> (state,state))
putState :: state -> State state()
putState new = State(\_ -> (new,()))
mapTreeM :: (Num a) => (a -> State state b) -> Tree a -> State state (Tree b)
mapTreeM f (Leaf a) =
f a >>= (\b -> return (Leaf b))
mapTreeM f (Branch lhs rhs) = do
lhs' <- mapTreeM f lhs
rhs' <- mapTreeM f rhs
return (Branch lhs' rhs')
numberTree :: (Num a) => Tree a -> State a (Tree (a,a))
numberTree tree = mapTreeM number tree
where number v = do
cur <- getState
putState(cur+v)
return (v,cur+v)
-- An instance of a tree
testTree = (Branch
(Branch
(Leaf 7) (Branch (Leaf (-1)) (Leaf 3)))
(Branch
(Leaf (-2)) (Leaf (-20))))
runStateM :: State state a -> state -> a
runStateM (State f) st = snd (f st)
main :: IO()
main = print $ runStateM (numberTree testTree) 0
你想要monad變壓器嗎? –
你可以使用mtl /變形金剛.... – alternative