我正试图扭转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
。即使我觉得这样做很难,我也无法解决这个问题。
答案 0 :(得分:2)
Zeroth ,清理您的代码。你不需要那么多的parens,你应该避免重复计算。 fst
和snd
两次同样的事情?咩。更好地使用模式匹配:
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