【问题标题】:Return tree for function with non-binary tree具有非二叉树的函数的返回树
【发布时间】:2017-02-05 04:52:03
【问题描述】:

我有一棵非二叉树:

data MultTree b = DataNode b | IndexNode Int Int [MultTree b] deriving (Show)

注意DataNode's 被视为树叶,IndexNode's 被视为树枝。

现在我尝试在IndexNode 中实现,较小的Int 值设置为子树的DataNode 的最小值,而较大的Int 值设置为DataNode 的最大值子树。

对于没有子树的IndexNode's,较小的Int 值设置为minBound::Int,较大的值设置为maxBound::Int

这是我目前的功能:

dataInterval:: (Ord a) => MultTree a -> MultTree a
dataInterval (DataNode x) = (DataNode x)
dataInterval(IndexNode x y [])
      | x > y  = (IndexNode (maxBound :: Int) (minBound :: Int) [])
      | x < y  = (IndexNode (minBound :: Int) (maxBound :: Int) [])
      | x == y = (IndexNode x y [])
datenInterval (IndexNode x y subtrees)
      | x > y  = (IndexNode (maxValue subtrees) (minValue subtrees) (map (dataInterval subtrees)))
      | x < y  = (IndexNode (minValue subtrees) (maxValue subtrees) (map (dataInterval subtrees)))
      | x == y = (IndexNode x y (map (dataInterval subtrees)))

必须递归调用函数dataInterval

现在我不知道该怎么做,因为dataInterval 需要一棵树,但不知何故我必须调用完整的列表。 dataInterval 不允许这样做。

问题:如何使用列表中的子树递归调用dataInterval?那么subtrees列表的每一棵树都会被调用?

我认为它可能是一些类似地图的功能,但返回的是子树而不是列表。

目前错误消息如下所示:

无法匹配预期类型 MultTree a2 具有实际类型 [MultTree a] * 在 datenIntervalle 的第一个参数中,即子树 在map的第一个参数中,即(datenIntervalle subtrees) 在 IndexNode 的第三个参数中,即 (地图(datenIntervalle 子树))

示例树和完整代码:

t2 :: MultTree Int
t2 = IndexNode 3 42 [IndexNode 7 8 [DataNode 3, DataNode 5, DataNode 7, DataNode 9], DataNode 6, IndexNode 10 23 [DataNode 99, DataNode 78, DataNode 24]]

dataList:: MultTree a -> [a]
dataList(DataNode x) = [x]
dataList(IndexNode _ _ subtress) = concat' (map dataList subtress)

maxValue :: (Ord a) => MultTree a -> a
maxValue tree = maximum (dataList tree)

minValue :: (Ord a) => MultTree a -> a
minValue tree = minimum (dataList tree)

dataInterval:: (Ord a) => MultTree a -> MultTree a
dataInterval(DataNode x) = (DataNode x)
dataInterval(IndexNode x y [])
      | x > y  = (IndexNode (maxBound :: Int) (minBound :: Int) [])
      | x < y  = (IndexNode (minBound :: Int) (maxBound :: Int) [])
      | x == y = (IndexNode x y [])
dataInterval(IndexNode x y subtrees)
      | x > y  = (IndexNode (maxValue subtrees) (minValue subtrees) (map (dataInterval subtrees)))
      | x < y  = (IndexNode (minValue subtrees) (maxValue subtrees) (map (dataInterval subtrees)))
      | x == y = (IndexNode x y (map (dataInterval subtrees)))

【问题讨论】:

  • 您的 dataIntervalsubtrees minValuemaxValue 未定义,afaik?
  • @WillemVanOnsem :对不起,我已经更新了我的问题。
  • 如果你说:“现在我尝试在 IndexNode 中实现,较小的 Int 值设置为子树的最小 DataNode,而较大的 Int 值设置为子树的最大 DataNode。”由于 IndexNode Int Int ...,不需要类型 b 是 Int 吗?此外,为了澄清,DataNodes 总是树的叶子吗?
  • @SlavenGlumac:在我的解释中是“价值”缺失。我已经更新了我的帖子。因此 IndexNode 的较小 int 设置为您可以在子树的叶子中找到的最小值。 IndexNode 的较大 Int 设置为您可以在子树的叶子中找到的最大值。是的,DataNode 总是叶子。
  • 你想要map dataInterval subtrees 而不是map (dataInterval subtrees)——这实际上正是类型错误告诉你的——除了看起来你的代码编译得很好。

标签: haskell tree


【解决方案1】:

我将发布您的问题的答案,同时回答您的最后一条评论:

我已移除弯曲支架并收到错误消息。如果您发布一些代码,我将不胜感激。我的错误消息:无法将预期类型 MultTree Int' 与实际类型 [MultTree a]' 匹配

这里的问题是您指定了minBound :: Int 的类型。但是在你的函数类型中,你说你有任何类型的树a,即Ord

dataInterval:: (Ord a) => MultTree a -> MultTree a

所以,Int 不等于 a。如果你不希望你的树是多态的,你可以只使用 dataInterval :: MultTree Int -&gt; MultTree Int 例如。 但这不是最好的解决方案。您可以将minBoundmaxBound 用于多态类型,但您需要在类型签名中将Bounded 约束添加到a。而且您不需要在函数中指定 minBound 的类型,因为 Haskell 具有类型推断功能。所以这里是完整的工作示例(我还删除了一些 () 因为 Haskell 不是 Lisp):

data MultTree b = DataNode b | IndexNode b b [MultTree b] deriving (Show)

t2 :: MultTree Int
t2 = IndexNode 3 42 [ IndexNode 7 8 [ DataNode 3
                                     , DataNode 5
                                     , DataNode 7
                                     , DataNode 9
                                     ]
                    , DataNode 6
                    , IndexNode 10 23 [ DataNode 99
                                      , DataNode 78
                                      , DataNode 24
                                      ]
                    ]

dataList :: MultTree a -> [a]
dataList (DataNode x)             = [x]
dataList (IndexNode _ _ subtrees) = flattenSubtrees subtrees

flattenSubtrees :: [MultTree a] -> [a]
flattenSubtrees = concatMap dataList

maxValue :: Ord a => [MultTree a] -> a
maxValue trees = maximum (flattenSubtrees trees)

minValue :: Ord a => [MultTree a] -> a
minValue trees = minimum (flattenSubtrees trees)

dataInterval :: (Bounded a, Ord a) => MultTree a -> MultTree a
dataInterval (DataNode x) = DataNode x
dataInterval node@(IndexNode x y [])
      | x > y  = IndexNode maxBound minBound []
      | x < y  = IndexNode minBound maxBound []
      | x == y = node
dataInterval (IndexNode x y subtrees)
      | x > y  = IndexNode (maxValue subtrees) (minValue subtrees) mappedSubtrees
      | x < y  = IndexNode (minValue subtrees) (maxValue subtrees) mappedSubtrees
      | x == y = IndexNode x y mappedSubtrees
  where
    mappedSubtrees = map dataInterval subtrees

我想注意到这个函数实现效率不高。因为每次需要评估最小值和最大值时都会遍历整棵树,而实际上在找到subtrees 的结果后仅遍历最后一层就足够了。 t2 的函数调用结果为:

ghci> dataInterval t2 
IndexNode 3 99 [IndexNode 3 9 [DataNode 3,DataNode 5,DataNode 7,
DataNode 9],DataNode 6,IndexNode 24 99 [DataNode 99,DataNode 78,
DataNode 24]]

【讨论】:

  • flattenSubtrees = concatMap dataList 为什么这里不应该是一个参数?喜欢flattenSubtrees = concatMap dataList subtrees
  • @jublikon 因为我在这里使用了 eta-reduction。 flattenSubtrees = concatMap dataList subtrees 不是有效定义,因为编译器不知道 subtrees 是什么。其他有效定义是flattenSubtrees subtrees = concatMap dataList subtrees,但正如我所说,这个定义与flattenSubtrees = concatMap dataList 是等价的。或者用人类的话来说,您可以删除=符号左右部分的常用后缀。
猜你喜欢
  • 1970-01-01
  • 2017-04-14
  • 2017-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 2020-08-24
相关资源
最近更新 更多