Haskell 从边列表构造树:缺少叶节点

Haskell 从边列表构造树:缺少叶节点,haskell,ghci,Haskell,Ghci,我编写了下面的代码来构造一棵树,该树具有给定的顶点以及顶点之间的连接列表 type Connection = (Int,Int) data Tree = Leaf Int | Node Int [Tree] deriving (Eq,Read,Show) makeTree :: Int -> [Connection] -> Tree makeTree x [] = Leaf x makeTree indx connections = Node indx otherTrees wh

我编写了下面的代码来构造一棵树,该树具有给定的顶点以及顶点之间的连接列表

type Connection = (Int,Int)
data Tree = Leaf Int | Node Int [Tree] deriving (Eq,Read,Show)

makeTree :: Int -> [Connection] -> Tree
makeTree x [] = Leaf x
makeTree indx connections =  Node indx otherTrees where
  otherTrees = [makeTree i cx | i <- directConnections, let cx = removeConnectionsTo indx connections]
  directConnections = map (\(x,y) -> if (x == indx) then y else x) $ filter (\(x,y) -> x == indx || y   == indx) connections

removeConnectionsTo :: Int -> [Connection] -> [Connection]
removeConnectionsTo indx = filter (\(x,y) ->    x /= indx && y /= indx)
类型连接=(Int,Int)
数据树=叶Int |节点Int[树]派生(Eq,读取,显示)
makeTree::Int->[连接]->树
makeTree x[]=叶x
makeTree indx connections=节点indx otherTrees,其中
otherTrees=[makeTree i cx|i if(x==indx)那么y else x)$filter(\(x,y)->x==indx|y==indx)连接
removeConnectionsTo::Int->[Connection]->[Connection]
将连接移除到indx=filter(\(x,y)->x/=indx&&y/=indx)
出于某种原因,下面的输入给了我令人惊讶的不同结果:

maketree1[(1,2)、(1,3)]
给我
Node 1[叶2,叶3]

maketree1[(1,2),(1,5),(2,3),(2,4),(5,6),(5,7)]
给了我
节点1[节点2[节点3[],节点4[],节点5[节点6[],节点7[].

我正在OS X 10.8.2上运行GHCi 7.4.1版


我不明白为什么我在第一个示例中两次得到了Leaf(正确),但在第二个示例中得到了子树列表为空的节点(不正确)。

一个快速解决方法是,在决定是构建
Leaf
还是
节点之前,只需检查
其他树是否为空,例如

makeTree indx connections
  | null otherTrees = Leaf indx
  | otherwise       = Node indx otherTrees
  where ...  
为了了解这里发生了什么,让我们添加一点工具:

import Debug.Trace

makeTree :: Int -> [Connection] -> Tree
makeTree ix cs | traceShow (ix, cs) False = undefined
makeTree x [] = ... -- leave rest of the function as before
现在将其加载到GHCi中,让我们看看递归调用是什么:

> import Control.DeepSeq
> (show $ makeTree 1 [(1,2),(1,5),(2,3),(2,4),(5,6),(5,7)]) `deepseq` ()
(1,[(1,2),(1,5),(2,3),(2,4),(5,6),(5,7)])
(2,[(2,3),(2,4),(5,6),(5,7)])
(3,[(5,6),(5,7)])
(4,[(5,6),(5,7)])
(5,[(2,3),(2,4),(5,6),(5,7)])
(6,[(2,3),(2,4)])
(7,[(2,3),(2,4)])
()

如您所见,第二个参数中的列表不是空的,这就是为什么它与函数的第一种情况不匹配的原因,因此您需要像我的示例中那样添加一些额外的检查,或者确保过滤掉其余的连接。

您希望得到什么结果?第二个答案应该包含“叶3”而不是“节点3[]”等。我对这个问题投了否决票,因为标题没有帮助,内容读起来有点像“请修复我的代码”没有任何明确的调查证据等@BenMillwood:现在改进了标题和问题。你的解决方案奏效了,但我仍然不明白为什么我的解决方案没有奏效。调用函数时,函数声明是按声明顺序选择的,因此
makeTree x[]=Leaf x
应该首先匹配,不是吗?它不匹配,因为第二个参数中的列表不是空的。在向下到节点的路径上,从列表中删除的唯一连接是提到其祖先的连接,因此,例如,当您到达
makeTree 7
时,
连接仍然有
[(2,3)、(2,4)]
在里面。啊,我花了一段时间才弄明白!感谢您提供有关DeepSeq和trace的信息-它们会派上用场的:)