生成所有可能的树
Generate All Possible Trees
给定以下数据类型定义:
data FormTree = Empty | Node FormTree FormTree deriving Show
我想编写一个函数来生成一个无限列表,其中包含按长度排序的所有可能的树,例如节点数量。
下面的代码几乎可以满足我的需要,但它每次都通过插入额外的节点来降低右侧的树,但我需要它在两侧交替。
allPossibleTrees :: [FormTree]
allPossibleTrees = Empty : [Node x y | x <- recursive, y <- recursive]
where recursive = allPossibleTrees
正在执行
take 5 allPossibleTrees
给出:
[Empty,Node Empty Empty,Node Empty (Node Empty Empty),Node Empty (Node Empty (Nodes Empty Empty)),Node Empty (Node Empty (Node Empty (Node Empty Empty)))]
但它应该是这样的:
[Empty,Node Empty Empty,Node (Node Empty Empty) Empty,Node Empty (Node Empty Empty),Node (Node Empty Empty) (Node Empty Empty)]
列表理解
[ (x,y) | x<-[1..] , y<-[1..] ]
首先考虑 x=1
并为所有可能的 y
构建所有对 (1,y)
。然后是 x=2
和所有 (2,y)
对。等等。
然而,(1,y)
对有无限多,所以x=2
只会在无限长的时间后才会被考虑——也就是说,根本不会。
您的代码遇到了同样的问题。
要查看可能的解决方案,您可以参考this related question利用Omega monad在所有情况下实现公平调度。
一种方法是跟踪树的大小(即使用的 Node
构造函数的数量。)
假设你有一个像这样的函数,它使用 n 个节点构造函数返回树:
treesOfSize :: Int -> [FormTree]
那么allTrees
可以定义为:
allTrees = concatMap treesOfSize [0..]
treesOfSize
的定义是可以递归定义的,我会让你弄清楚:
treesOfSize 0 = [Empty]
treesOfSize n = [ Node t1 t2 | ... ]
这是一个不错的技巧,让人联想到标准的斐波那契数字技巧。我们将构建一个惰性列表;列表的每个成员将是具有给定节点数的所有树的列表。只有一棵没有节点的树,Empty
,这将作为我们的基本情况。要构建具有 n
个节点的所有树,我们假设我们已经知道如何构建具有 0
、1
、2
、...、[=18 的树=] 节点。然后我们将不确定地选择一对总和为 n-1
的配对,并在顶部粘贴一个 Node
。
在代码中:
import Control.Monad
import Data.List
sizes :: [[FormTree]]
sizes = [Empty] : (map go . drop 1 . inits) sizes where
go smaller = do
(ls, rs) <- zip smaller (reverse smaller)
liftM2 Node ls rs
然后我们可以简单地定义 allPossibleTrees = concat sizes
如果需要的话。前几条:
*Main> mapM_ print (take 4 sizes)
[Empty]
[Node Empty Empty]
[Node Empty (Node Empty Empty),Node (Node Empty Empty) Empty]
[Node Empty (Node Empty (Node Empty Empty)),Node Empty (Node (Node Empty Empty) Empty),Node (Node Empty Empty) (Node Empty Empty),Node (Node Empty (Node Empty Empty)) Empty,Node (Node (Node Empty Empty) Empty) Empty]
我们可以进行快速完整性检查:
*Main> take 10 (map length sizes)
[1,1,2,5,14,42,132,429,1430,4862]
...这确实是前十个 Catalan numbers,所以我们可能猜对了!
control-monad-omega
库似乎可以用您的原始代码解决问题:
{-# LANGUAGE MonadComprehensions #-}
import Control.Monad.Omega
data Empty = Empty | Node Empty Empty deriving Show
allPossibleTrees :: [Empty]
allPossibleTrees = Empty :
runOmega [Node x y | x <- each allPossibleTrees, y <- each allPossibleTrees]
前 10 棵树我觉得不错:
*Main> mapM_ print $ take 10 allPossibleTrees
Empty
Node Empty Empty
Node Empty (Node Empty Empty)
Node (Node Empty Empty) Empty
Node Empty (Node Empty (Node Empty Empty))
Node (Node Empty Empty) (Node Empty Empty)
Node (Node Empty (Node Empty Empty)) Empty
Node Empty (Node (Node Empty Empty) Empty)
Node (Node Empty Empty) (Node Empty (Node Empty Empty))
Node (Node Empty (Node Empty Empty)) (Node Empty Empty)
给定以下数据类型定义:
data FormTree = Empty | Node FormTree FormTree deriving Show
我想编写一个函数来生成一个无限列表,其中包含按长度排序的所有可能的树,例如节点数量。
下面的代码几乎可以满足我的需要,但它每次都通过插入额外的节点来降低右侧的树,但我需要它在两侧交替。
allPossibleTrees :: [FormTree]
allPossibleTrees = Empty : [Node x y | x <- recursive, y <- recursive]
where recursive = allPossibleTrees
正在执行
take 5 allPossibleTrees
给出:
[Empty,Node Empty Empty,Node Empty (Node Empty Empty),Node Empty (Node Empty (Nodes Empty Empty)),Node Empty (Node Empty (Node Empty (Node Empty Empty)))]
但它应该是这样的:
[Empty,Node Empty Empty,Node (Node Empty Empty) Empty,Node Empty (Node Empty Empty),Node (Node Empty Empty) (Node Empty Empty)]
列表理解
[ (x,y) | x<-[1..] , y<-[1..] ]
首先考虑 x=1
并为所有可能的 y
构建所有对 (1,y)
。然后是 x=2
和所有 (2,y)
对。等等。
然而,(1,y)
对有无限多,所以x=2
只会在无限长的时间后才会被考虑——也就是说,根本不会。
您的代码遇到了同样的问题。
要查看可能的解决方案,您可以参考this related question利用Omega monad在所有情况下实现公平调度。
一种方法是跟踪树的大小(即使用的 Node
构造函数的数量。)
假设你有一个像这样的函数,它使用 n 个节点构造函数返回树:
treesOfSize :: Int -> [FormTree]
那么allTrees
可以定义为:
allTrees = concatMap treesOfSize [0..]
treesOfSize
的定义是可以递归定义的,我会让你弄清楚:
treesOfSize 0 = [Empty]
treesOfSize n = [ Node t1 t2 | ... ]
这是一个不错的技巧,让人联想到标准的斐波那契数字技巧。我们将构建一个惰性列表;列表的每个成员将是具有给定节点数的所有树的列表。只有一棵没有节点的树,Empty
,这将作为我们的基本情况。要构建具有 n
个节点的所有树,我们假设我们已经知道如何构建具有 0
、1
、2
、...、[=18 的树=] 节点。然后我们将不确定地选择一对总和为 n-1
的配对,并在顶部粘贴一个 Node
。
在代码中:
import Control.Monad
import Data.List
sizes :: [[FormTree]]
sizes = [Empty] : (map go . drop 1 . inits) sizes where
go smaller = do
(ls, rs) <- zip smaller (reverse smaller)
liftM2 Node ls rs
然后我们可以简单地定义 allPossibleTrees = concat sizes
如果需要的话。前几条:
*Main> mapM_ print (take 4 sizes)
[Empty]
[Node Empty Empty]
[Node Empty (Node Empty Empty),Node (Node Empty Empty) Empty]
[Node Empty (Node Empty (Node Empty Empty)),Node Empty (Node (Node Empty Empty) Empty),Node (Node Empty Empty) (Node Empty Empty),Node (Node Empty (Node Empty Empty)) Empty,Node (Node (Node Empty Empty) Empty) Empty]
我们可以进行快速完整性检查:
*Main> take 10 (map length sizes)
[1,1,2,5,14,42,132,429,1430,4862]
...这确实是前十个 Catalan numbers,所以我们可能猜对了!
control-monad-omega
库似乎可以用您的原始代码解决问题:
{-# LANGUAGE MonadComprehensions #-}
import Control.Monad.Omega
data Empty = Empty | Node Empty Empty deriving Show
allPossibleTrees :: [Empty]
allPossibleTrees = Empty :
runOmega [Node x y | x <- each allPossibleTrees, y <- each allPossibleTrees]
前 10 棵树我觉得不错:
*Main> mapM_ print $ take 10 allPossibleTrees
Empty
Node Empty Empty
Node Empty (Node Empty Empty)
Node (Node Empty Empty) Empty
Node Empty (Node Empty (Node Empty Empty))
Node (Node Empty Empty) (Node Empty Empty)
Node (Node Empty (Node Empty Empty)) Empty
Node Empty (Node (Node Empty Empty) Empty)
Node (Node Empty Empty) (Node Empty (Node Empty Empty))
Node (Node Empty (Node Empty Empty)) (Node Empty Empty)