gpt4 book ai didi

haskell - 为什么我们必须使用 state monad 而不是直接传递 state?

转载 作者:行者123 更新时间:2023-12-04 02:55:12 27 4
gpt4 key购买 nike

有人可以举一个简单的例子,其中 state monad 比直接传递 state 更好吗?

bar1 (Foo x) = Foo (x + 1)

对比
bar2 :: State Foo Foo
bar2 = do
modify (\(Foo x) -> Foo (x + 1))
get

最佳答案

状态传递通常是乏味的、容易出错的并且阻碍重构。例如,尝试按后序标记二叉树或玫瑰树:

data RoseTree a = Node a [RoseTree a] deriving (Show)

postLabel :: RoseTree a -> RoseTree Int
postLabel = fst . go 0 where
go i (Node _ ts) = (Node i' ts', i' + 1) where

(ts', i') = gots i ts

gots i [] = ([], i)
gots i (t:ts) = (t':ts', i'') where
(t', i') = go i t
(ts', i'') = gots i' ts

在这里,我必须以正确的顺序手动标记状态,传递正确的状态,并且必须确保标签和子节点在结果中的顺序正确(请注意,天真使用 foldrfoldl 为 child 节点可能很容易导致不正确的行为)。

另外,如果我尝试将代码更改为预购,我必须进行容易出错的更改:
preLabel :: RoseTree a -> RoseTree Int
preLabel = fst . go 0 where
go i (Node _ ts) = (Node i ts', i') where -- first change

(ts', i') = gots (i + 1) ts -- second change

gots i [] = ([], i)
gots i (t:ts) = (t':ts', i'') where
(t', i') = go i t
(ts', i'') = gots i' ts

例子:
branch = Node ()
nil = branch []
tree = branch [branch [nil, nil], nil]
preLabel tree == Node 0 [Node 1 [Node 2 [],Node 3 []],Node 4 []]
postLabel tree == Node 4 [Node 2 [Node 0 [],Node 1 []],Node 3 []]

对比状态单子(monad)解决方案:
import Control.Monad.State
import Control.Applicative

postLabel' :: RoseTree a -> RoseTree Int
postLabel' = (`evalState` 0) . go where
go (Node _ ts) = do
ts' <- traverse go ts
i <- get <* modify (+1)
pure (Node i ts')

preLabel' :: RoseTree a -> RoseTree Int
preLabel' = (`evalState` 0) . go where
go (Node _ ts) = do
i <- get <* modify (+1)
ts' <- traverse go ts
pure (Node i ts')

这段代码不仅更简洁、更容易正确编写,而且导致订单前或订单后标签的逻辑更加透明。

PS:奖金适用风格:
postLabel' :: RoseTree a -> RoseTree Int
postLabel' = (`evalState` 0) . go where
go (Node _ ts) =
flip Node <$> traverse go ts <*> (get <* modify (+1))

preLabel' :: RoseTree a -> RoseTree Int
preLabel' = (`evalState` 0) . go where
go (Node _ ts) =
Node <$> (get <* modify (+1)) <*> traverse go ts

关于haskell - 为什么我们必须使用 state monad 而不是直接传递 state?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31475770/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com