Joe*_*nge 1 haskell state-monad
我有以下数据结构和功能:
data BTree a = BLeaf | BNode (BTree a) a (BTree a) deriving (Show, Eq)
freshNodesS :: BTree String -> State [String] (BTree String)
freshNodesS BLeaf = return BLeaf
freshNodesS (BNode l m r) = do l' <- freshNodesS l
let m' = getFresh m s
let s' = m : s
r' <- freshNodesS r s'
return (BNode l' m' r')
Run Code Online (Sandbox Code Playgroud)
有一个问题,我实际上想使用freshNodesS l应该给出输出的状态(BTree String, [String]),但是在我不能使用的 do 块中(l', s) <- freshNodesS l,我看到的唯一选择是将所有内容都放在 lambda 函数中。但是有没有办法我仍然可以使用 do 符号?
在@chi 所说的之后,我做了这个:
freshNodesS BLeaf = return BLeaf
freshNodesS (BNode l m r) = do l' <- freshNodesS l
m' <- getFreshS m
r' <- freshNodesS r
return (BNode l' m' r')
getFreshS :: String -> State [String] String
getFreshS x = state $ (\s -> let newx = getFresh x s in (newx, newx: s))
Run Code Online (Sandbox Code Playgroud)
那奏效了。
Statemonad的全部意义在于自动传递状态,而无需您明确地这样做。几乎没有函数应该s作为参数获取或返回它。
例如,
let m' = getFresh m s
Run Code Online (Sandbox Code Playgroud)
是可疑的,它可能应该阅读
m' <- getFresh m
Run Code Online (Sandbox Code Playgroud)
我们会在哪里getFresh :: String -> State [String] String。
整个代码应该读为
do l' <- freshNodesS l
m' <- getFresh m
r' <- freshNodesS r
return (BNode l' m' r')
Run Code Online (Sandbox Code Playgroud)
请注意没有s或s'从未被提及。这应该看起来像命令式代码,其中每个函数调用都会修改可变状态变量,即使代码没有明确提及。
现在,getFresh您将不得不与州打交道,因为没有办法解决这个问题。如果您的Statemonad 是标准的,您可以使用get和访问状态put。你可能需要类似的东西
getFresh :: String -> State [String] String
getFresh m = do
s <- get -- read the current state
let m' = ... -- compute a fresh name m'
let s' = m' : s -- mark m' as used
put s' -- write the current state
return m'
Run Code Online (Sandbox Code Playgroud)