简体   繁体   English

Haskell 来自参数化二叉搜索树的最大值

[英]Haskell max from parameterized binary search tree

I have this function to get min value from my BST, type Int:我有这个 function 从我的 BST 中获取最小值,输入 Int:

maxBST    :: BST Int -> Int
maxBST    Nil  = -1000000
maxBST    (Node left value right)  = max (maxBST left) (max value (maxBST right))

Now I want to remake this function so that it also works for parameterized BST, like this:现在我想重新制作这个 function 以便它也适用于参数化 BST,如下所示:

maxBST       :: (Ord t) => BST t -> t
maxBST Nil   =  //?
maxBST (Node left value right) = max (maxBST left) (max value (maxBST right))

The problem here is to find the correct //?这里的问题是找到正确的 //? value, so that it's minimum for type t .值,因此它是类型t的最小值。 Do you have any suggestion for this?你对此有什么建议吗?

The fundamental problem here is that your type signature (like that of maximum ) is a lie.这里的根本问题是您的类型签名(如maximum的类型签名)是一个谎言。 You cannot guarantee to produce the maximal element from a data structure that may contain no elements.您不能保证从可能不包含任何元素的数据结构中生成最大元素。 A special sentinel value can paper over this issue in some cases, but even in those cases it breaks down if you look carefully.在某些情况下,一个特殊的哨兵值可以掩盖这个问题,但即使在那些情况下,如果你仔细观察,它也会崩溃。 What is the minimum element of Node Nil -2000000 Nil ? Node Nil -2000000 Nil的最小元素是多少? This is a nonempty tree, so you should be able to get its maximum, but your implementation returns -1000000 instead, as though the tree were empty!这是一棵非空树,因此您应该能够获得它的最大值,但您的实现却返回 -1000000,就好像树是空的一样!

One thing you could try that would do a better job of sweeping the problem under the rug would be to add a Bounded constraint, so that you could use minBound as the "neutral" element.您可以尝试的一件事是添加 Bounded 约束,以便更好地解决问题,这样您就可以将minBound用作“中性”元素。 Then at least you don't get erroneous results as in my example, but you still can't tell an empty tree from a tree containing only the minimum.那么至少您不会像我的示例那样得到错误的结果,但是您仍然无法从仅包含最小值的树中分辨出空树。

Better is to adjust your type signature to tell the truth.更好的办法是调整您的类型签名以说实话。 You can return Maybe t instead of just t , using Nothing to indicate "sorry, this tree was empty".您可以返回Maybe t而不仅仅是t ,使用 Nothing 来表示“抱歉,这棵树是空的”。 As for implementation, you can just the the obvious brute-force thing of pattern-matching on the recursive calls - it's clunky, but it works.至于实现,您可以在递归调用上进行模式匹配这一明显的蛮力操作——它很笨重,但它确实有效。

Better still, though, would be to implement Foldable for your tree type (a good idea in any case), so that you can take advantage of its toList .不过,更好的办法是为您的树类型实现 Foldable(在任何情况下都是一个好主意),这样您就可以利用它的toList Presuming that you have done so, this maximum function becomes easy:假设您已经这样做了,这个最大值 function 就变得容易了:

maxBST t = case toList t of
  [] -> Nothing
  xs -> Just $ maximum xs

I agree with @amalloy's answer, that returning a Maybe type is the best approach here.我同意@amalloy 的回答,返回Maybe类型是这里最好的方法。

However, there is another approach if you are determined to always return an "actual value" and have it be a sensible "minimum" for the type.但是,如果您决定始终返回一个“实际值”并使其成为该类型的合理“最小值”,则还有另一种方法。 And that is to alter the type signature so that the elements of the tree must be of a type that is an instance of Bounded as well as Ord .那就是改变类型签名,以便树的元素必须是BoundedOrd的实例的类型。 This would be:这将是:

maxBST       :: (Ord t, Bounded t) => BST t -> t
maxBST Nil   =  minBound
maxBST (Node left value right) = max (maxBST left) (max value (maxBST right))

Note that, although this will work on Int , it won't be identical to your original function, because the minBound for Int is much less than -1000000.请注意,尽管这适用于Int ,但它不会与您原来的 function 相同,因为IntminBound远小于 -1000000。

Don't goto nil, just destructure left and right and see if both of them are nil and handle the cases不要转到 nil,只需解构 left 和 right,看看它们是否都为 nil 并处理这些情况

maxBST Nil = error "your function shouldn't reach here"
maxBST (Node Nil value Nil) = value
maxBST (Node left@(Node _ _ _) value Nil) = max (maxBST left) value
maxBST (Node Nil value right@(Node _ _ _)) = max value (maxBST right)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM