找到归纳定义树的叶子

时间:2009-08-06 08:18:23

标签: haskell functional-programming

所以,我有一个类型的函数:

genTree :: Node -> [Nodes]

给定节点,此函数在树中生成该节点的子集。该函数可以再次应用于这些子节点以生成它们的子节点,直到它最终生成一个没有子节点的节点,即genTree返回[]的节点。

我想要做的是,给定一个起始节点,生成树中所有以叶为根的叶节点的列表。

有什么建议吗?

4 个答案:

答案 0 :(得分:4)

让我们稍微概括一下:

leaves :: (a -> [a]) -> a -> [a]
leaves tree x = case (tree x) of
                  [] -> [x] 
                  -- the node x has no children and is therefore a leaf
                  xs -> concatMap (leaves tree) xs
                  -- otherwise get list of all leaves for each child and concatenate them

应用静态参数变换(http://hackage.haskell.org/trac/ghc/ticket/888),我们得到

leaves :: (a -> [a]) -> a -> [a]
leaves tree x = leaves' x where
  leaves' x = case (tree x) of
                [] -> [x] 
                xs -> concatMap leaves' xs

将其用作

leaves genTree root

或者如果确实希望它仅与genTree一起使用,请将其内联到定义中:

leaves1 root = case (genTree x) of
                 [] -> [x] 
                 xs -> concatMap leaves1 xs

这在道德上等同于第二个答案。

答案 1 :(得分:4)

Martijn的答案中的函数生成树中所有节点的列表。您可以使用此列表并过滤掉没有子节点的节点来获取叶子:

nodes root  = root : concatMap nodes (genTree root)
leaves root = filter (null . genTree) (nodes root)

如果您愿意,也可以将这两个函数合并为一个直接生成叶子列表:

leaves node
   | null children = [node]
   | otherwise     = concatMap leaves children
   where children = genTree node

答案 2 :(得分:2)

(不完全是问题的答案,但相关)

我喜欢将a的树代表为“ListT [] a”。 (来自ListT hackage包中的List

然后这个问题的答案就是使用函数lastL

Monad m => ListT m a”是一个包含“a”的monadic列表,其中试图获取下一个列表项(可能发现没有这样的项)是“{{1}中的monadic动作{1}}”。

m的使用示例 - 从用户读取数字直到用户不输入数字并在每次输入后打印数字总和的程序:

ListT

main = execute . joinM . fmap print . scanl (+) 0 . fmap (fst . head) . takeWhile (not . null) . fmap reads . joinM $ (repeat getLine :: ListT IO (IO String)) repeatscanl来自takeWhile。它们适用于常规列表和monadic列表。

Data.List.Class

如果您熟悉Python,python迭代器/生成器是“joinM :: List l => l (ItemM l a) -> l a -- (l = ListT IO, ItemM l = IO) execute :: List l => l a -> ItemM l () -- consume the whole list and run its actions ”。

当使用ListT IO而不是[]作为monadic列表的monad时,结果是树。为什么?想象一个列表,其中下一个项目是列表monad中的一个动作 - 列表monad意味着有几个选项,因此有几个“下一个项目”,这使它成为一个树。

您可以使用{{1}构建具有高阶函数(如上例所示)或IO的monadic列表,或使用python-generator表示法(使用cons)构建monadic列表来自hackage中yield包的monad变换器。

免责声明:GeneratorTgenerator并未广泛使用。我写了这些,除了我自己,我不知道任何其他用户。有几个等效ListT的用户,例如来自Haskell wiki,GeneratorT的用户,以及其他用户。

答案 3 :(得分:0)

flatten node = node : concatMap flatten (genTree node)