haskell二叉树函数
我必须用haskell编写一个函数来检查两个二叉树是否是彼此的镜像。这是我到目前为止所拥有的,但我不知道True&&areMirrorImages l1 r2&&areMirrorImages r1 l2是否是正确的方法。我试图用递归调用areMirrorImages函数的结果来验证逻辑性和真实性haskell二叉树函数,haskell,binary-tree,Haskell,Binary Tree,我必须用haskell编写一个函数来检查两个二叉树是否是彼此的镜像。这是我到目前为止所拥有的,但我不知道True&&areMirrorImages l1 r2&&areMirrorImages r1 l2是否是正确的方法。我试图用递归调用areMirrorImages函数的结果来验证逻辑性和真实性 -- Tests whether two BinaryTrees are mirror images of one another areMirrorImages :: (Eq (BinaryTree
-- 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
如果BinaryTree有一个Eq的派生实例,我似乎无法找出问题所在可能您需要的唯一约束是Eq a。该派生实例将类似于:
instance Eq a => Eq (BinaryTree a) where
...
因此,知道可以比较a
是否相等,Haskell就会发现可以比较BinaryTree a
值是否相等
你的逻辑在我看来也可能是错误的。例如,除非left1==right2
和都是镜像,否则函数将返回False。除非left1和right2是对称的(假设aremrrorImages的实现是正确的),否则这两个参数不可能都是真的 需要Eq(二进制树a)
意味着您需要比较(测试Eq
a)两棵树。您不需要这样做,因为您正在测试树是否是彼此的镜像,而不是它们是否相等
树木什么时候是彼此的镜子?当键相同且相反的分支彼此镜像时
键是相同的: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
您的想法是正确的。我已经将您的版本稍微精简了一点,它似乎工作得很好:
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
需要是Eq
的实例。(即使我在数据声明中推导了Eq
)
条件-就像我说的,最后你只需要测试特定元素是否相等。检查left1==right2&&right1==left2
没有意义,因为它们不应该相等,所以这些分支应该是彼此的镜像
守卫而不是if——我认为守卫比if更漂亮
模式匹配-只在结尾处设置catch all False稍微干净一些(imho)
我最近一直在尝试学习QuickCheck,所以我也写出了这段代码来证明areMirrorImages是有效的
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)
我对BinaryTree
的arbitral
实例不是最好的;它只能制造出近乎平衡的树木。但我觉得它相当不错。还请注意,prop_mirror
仅测试何时为镜像图像
应返回True
;它不会暴露潜在的误报(尽管我相当肯定不会有)
我建议您编写一个普通的(未镜像的)相等函数和第二个镜像树的函数,然后说isMirrorOf x y=x==mirror y
?这样编写代码往往更清晰。True&&expr
是不必要的;它将始终计算为expr
,因此您可以直接删除True&&
。另请参阅注意,使用mirror
的此定义,您可以按照barsoap的建议编写areMirrorImages x y=x==mirror y
。(这将使prop\u mirror
变得毫无价值。)…但您可以添加prop\u mirror x=x==(mirror.mirror)x
。与流行的观点相反,无限并不是你在面对面的两面镜子中看到的东西。
*Main> quickCheck prop_mirror
+++ OK, passed 100 tests.