Haskell:从列表中构建一个树

时间:2014-02-07 20:25:15

标签: list haskell tree higher-order-functions

考虑以下类型:

data LTree a = Leaf a | Fork (LTree a) (LTree a)

现在考虑以下函数列出树的叶子及其深度

tolistdepth :: LTree a -> [(a,Int)]
tolistdepth (Leaf x) = [(x,0)]
tolistdepth (Fork e d) = map (\(x,n) -> (x,n+1)) (tolistdepth e ++ tolistdepth d)

我需要帮助来定义以下功能

build :: [(a, Int)] -> LTree a

计算第一个函数的反函数,以便

build (tolistdepth a) = a

我甚至不知道从哪里开始:)


我设法做了以下事情:

build :: [(a, Int)] -> LTree a
build xs = let ys= map (\(x, n) -> (Leaf x, n)) xs
           in SOMETHING iterateUntil SOMETHING (buildAssist ys)

buildAssist :: [(LTree a, Int)] -> [(LTree a, Int)]
buildAssist [] = []
buildAssist [x] = [x]
buildAssist (x@(t1, n1):y@(t2, n2):xs) = if n1 == n2 then ((Fork t1 t2), n1 - 1):buildAssist xs
                                                     else x:(buildAssist (y:xs))

这样,我想我已经处理了什么时候分叉。 现在,我如何在我的原始函数中使用buildAssist(如果buildAssist当然有用)?


我相信我已经弄清楚了。

如果有效,请告诉我:

build :: [(a,Int)] -> LTree a
build l = fst (buildaccum 0 l)

buildaccum :: Int -> [(a,Int)] -> (LTree a, [(a,Int)])
buildaccum n l@((a,b):t) |n==b = (Leaf a,t)
                         |n<b = (Fork e d, l2)
     where (e,l1) = buildaccum (n+1) l
           (d,l2) = buildaccum (n+2) l1

1 个答案:

答案 0 :(得分:6)

我会给你一个提示,它在解析列表时展示了一种有用的技巧。

这里真正起作用的是这样的功能:

build' :: [(a,Int)] -> (LTree a, [(a,Int)])

也就是说,build'返回LTree a,其余的输入列表尚未消耗。

在这种形式中,build'的定义如下:

build' [] = error "oops - bad input list"
build' ((a,n):xs) =
  if we are at a leaf node, return (LTree a, xs)
  if we decide we need to fork, then return (Fork e f,zs)
    where
      (e,ys) = build' ((a,n):xs)  -- parse the left branch
      (f,zs) = build' ys          -- parse the right branch

请注意,这只是伪代码,并且缺少重要的细节,我将其留作练习。

有趣的部分是如何在Fork案例中确定剩余的输入列表。 ys是解析左分支后的剩余输入,并将其作为输入提供给build'以获取正确的分支,并将该调用的剩余输入提供给build'({{1} }})作为原始zs调用的剩余输入返回。

更新

要使用起始值build'迭代函数f,直到某个条件x,请遵循以下公式:

p