haskell二叉树函数

时间:2011-02-20 21:19:33

标签: haskell binary-tree

我必须在haskell中编写一个函数来检查两个二叉树是否是彼此的镜像。这是我到目前为止,但我不知道是真的&& areMirrorImages l1 r2&& areMirrorImages r1 l2是正确的方法。我试图用递归调用areMirrorImages函数的结果来逻辑AND True。

-- Tests whether two BinaryTrees are mirror images of one another
areMirrorImages :: (Eq (BinaryTree a), Eq a) => BinaryTree a -> BinaryTree a -> Bool
areMirrorImages Empty Empty = True
areMirrorImages _ Empty = False
areMirrorImages Empty _     = False
areMirrorImages (Node x1 left1 right1) (Node x2 left2 right2) = 
    if (x1 == x2 && left1 == right2 && right1 == left2)
then True && (areMirrorImages left1 right2) && (areMirrorImages right1 left2)
else False 

这是我尝试编译时遇到的错误:

A2.hs:2:0:
    Non-type variables, or repeated type variables,
      in the constraint: Eq (BinaryTree a)
    (Use -fglasgow-exts to permit this)
    In the type signature:
      areMirrorImages :: (Eq (BinaryTree a), Eq a) =>
                         BinaryTree a -> BinaryTree a -> Bool

我似乎无法弄清楚出了什么问题

3 个答案:

答案 0 :(得分:5)

要求Eq (BinaryTree a)表示您需要比较(测试Eq uality)两棵树。您不需要这样做,因为您正在测试树是否是彼此的镜像,而不是它们是否相等。

树木什么时候互相镜像?当键是相同的并且相对的分支是彼此的镜像时。

关键是相同的:x1 == x2

相反的分支是镜像:areMirrorImages left1 right2 && areMirrorImages right1 left2

将其翻译成Haskell:

areMirrorImages (Node x1 left1 right1) (Node x2 left2 right2) = 
    x1 == x2 && areMirrorImages left1 right2 && areMirrorImages right1 left2

Haskell允许您编写简洁,直接的代码。无需使用if then else

答案 1 :(得分:1)

如果BinaryTree具有Eq的派生实例,那么您可能需要的唯一约束是Eq a。派生的实例看起来像:

instance Eq a => Eq (BinaryTree a) where
    ...

因此,知道可以比较a的相等性将允许Haskell确定可以比较您的BinaryTree a值是否相等。

你的逻辑看起来对我来说也许是错的。例如,除非 left1 == right2areMirrorImages left1 right2都为True,否则您的函数将返回False。假设isMirrorImages的正确实现,除非left1和right2是对称的,否则这些都不可能都是真的。

答案 2 :(得分:0)

你有正确的想法。我已经将你的版本缩减了一点,看起来效果很好:

data BinaryTree a = Empty | Node a (BinaryTree a) (BinaryTree a)
                  deriving(Show, Eq)

areMirrorImages :: (Eq a) => BinaryTree a -> BinaryTree a -> Bool
areMirrorImages (Node x1 left1 right1) (Node x2 left2 right2) 
    | x1 == x2  = areMirrorImages left1 right2 &&
                  areMirrorImages right1 left2
    | otherwise = False
areMirrorImages Empty Empty = True
areMirrorImages _ _ = False

那我改变了什么?

类型签名 - 最后,您只需要对树的元素调用==,因此只有a需要是{{1}的实例}。 (尽管我确实在数据声明中派生了Eq

条件 - 就像我说的那样,最后你只需要测试特定元素是否相等。检查Eq是否有意义,因为它们不应该相等,这些分支应该是彼此的镜像。

警卫而不是if - 我认为警卫比ifs更漂亮。

模式匹配 - 最后只需要捕获所有False,这样会更加清晰(imho)。

我最近一直在努力学习QuickCheck,所以我也抽出了这段代码来证明areMirrorImages有效。

left1 == right2 && right1 == left2

instance (Arbitrary a) => Arbitrary (BinaryTree a) where arbitrary = fromList `fmap` arbitrary fromList :: [a] -> BinaryTree a fromList [] = Empty fromList (x:xs) = Node x (fromList lhalf) (fromList rhalf) where (lhalf, rhalf) = splitAt (length xs `div` 2) xs mirror :: BinaryTree a -> BinaryTree a mirror Empty = Empty mirror (Node x l r) = Node x (mirror r) (mirror l) prop_mirror tree = areMirrorImages tree (mirror tree) Arbitrary的实例不是最好的;它只能制造几乎平衡的树木。但我认为它非常好。另请注意,BinaryTree仅测试prop_mirror何时应返回areMirrorImages;它没有暴露潜在的误报(尽管我很确定没有)。

True