给定是一个递归树结构
data Tree = Leaf Int | Node Tree Tree deriving Show
我想以保留树结构的方式对其进行规范化,但是使得叶子上的整数按深度顺序排列。我怎样才能做到这一点?我当前的设置代码如下所示:
myTree = Node (Leaf 3) (Node (Leaf 5) (Leaf 2))
myTree' = normalize myTree
-- preserve tree structure, but make Ints sequential in depths-first traversal
normalize :: Tree -> Tree
normalize = id -- todo: implement
main = do
print myTree -- prints : Node (Leaf 3) (Node (Leaf 5) (Leaf 2))
print myTree' -- should print: Node (Leaf 1) (Node (Leaf 2) (Leaf 3))
答案 0 :(得分:1)
如果不使用monad,您可以编写一个函数映射带有某种状态的树
mapLRS :: (s -> Int -> (s, Int)) -> s -> Tree -> (Tree, s)
mapLRS f s (Leaf x ) =
let (s', x') = f s x
in (Leaf x', s') -- the mapped leaf and the new state
mapLRS f s (Node l r) =
let (l', s' ) = mapLRS f s l -- the mapped left branch and the new state
(r', s'') = mapLRS f s' r -- the mapped right branch and the new state
in (Node l' r', s'')
现在
normalize :: Tree -> Tree
normalize = fst . mapWithStateLeftRight (\s _ -> (s + 1, s)) 1
使用monad可能更具可读性(f
与使用state
的简单性不一样。)
import Control.Monad.State
mapLRS :: (s -> (Int, s)) -> Tree -> State s Tree
mapLRS f (Leaf x) = Leaf <$> state f
mapLRS f (Node l r) = Node <$> mapLRS f l <*> mapLRS f r
normalize :: Tree -> Tree
normalize tree = evalState (mapLRS (\s -> (s, s + 1)) tree) 1
答案 1 :(得分:1)
执行此操作的标准方法是将当前标签记录在monad状态:
import Control.Monad.State
data Tree = Leaf Int | Node Tree Tree deriving (Show)
normalize :: Tree -> Tree
normalize t = evalState (go t) 1 where
go :: Tree -> State Int Tree
go (Leaf _) = Leaf <$> (get <* modify (+1))
go (Node l r) = Node <$> go l <*> go r
此解决方案将状态初始化为1
,然后遍历树,并在每次遇到Leaf
时将当前标签放在返回的Leaf
中并递增标签。
或者,我们可以派生Traversable
的{{1}}实例:
Tree
这的工作方式相同,但请注意,它依赖于派生的{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
import Control.Monad.State
data Tree a = Leaf a | Node (Tree a) (Tree a)
deriving (Show, Functor, Foldable, Traversable)
normalize :: Tree a -> Tree Int
normalize = (`evalState` 1) . traverse (\_ -> get <* modify (+1))
实例具有正确的遍历顺序这一事实。当然,如果我们想要一些其他订单,那么我们就必须编写自己的遍历。