Haskell:如何反转树的子项递归

时间:2016-03-18 20:11:55

标签: haskell recursion tree

我正试图扭转haskell中一棵树的孩子。树看起来像这样:

data Tree v e = Node v [(e,Tree v e)]  

目前,我使用这两个功能:

rev :: Tree v e -> Tree v e
rev (Node v []) = Node v []
rev (Node v xs) =
  let xs' = (rev'(snd (unzip xs)))
  in Node v (zip (fst (unzip xs)) (map rev xs'))


rev' :: [Tree v e] -> [Tree v e]
rev' [] = []
rev' (x:xs) = (rev' xs) ++ [x]  

我甚至不确定这是否100%有效。有没有办法在一个函数中递归递归?我觉得我的方式效率低下。我试图编写一个看起来像这样的函数:

revRec :: Tree v e -> Tree v e
revRec (Node v [])     = Node v []
revRec (Node v (x:xs)) = Node v (revRec xs ++ [x]) 

很明显,自revRec列表以来,我无法使用xs致电xs。即使我觉得这样做很难,我也无法解决这个问题。

1 个答案:

答案 0 :(得分:2)

Zeroth ,清理您的代码。你不需要那么多的parens,你应该避免重复计算。 fstsnd两次同样的事情?咩。更好地使用模式匹配:

rev :: Tree v e -> Tree v e
rev (Node v xs)
  = let (es, cs) = unzip xs
        xs' = rev' cs
    in Node v $ zip es (map rev xs')

rev' :: [Tree v e] -> [Tree v e]
rev' [] = []
rev' (x:xs) = rev' xs ++ [x]  

首先请注意,rev'并非特定于树木列表!它只是 标准reverse函数的 的低效实现,它适用于任何列表。

第二次,这种解压/拉链有点笨拙。您确定这实际上是您想要的行为:现在您只是反转子项列表,但元素的顺序保持不变。如果没有,那么你最好用一个反向和一个地图来做这一切:

rev :: Tree v e -> Tree v e
rev (Node v xs) = Node v . reverse $ map (\(e,c) -> (e, rev c)) xs

或者,甚至更好,

import Control.Arrow

rev (Node v xs) = Node v . reverse $ map (second rev) xs