У вас правильная идея. Я немного урезал вашу версию, и она, кажется, работает нормально:
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 - я думаю, что охранники красивее, чем ifs.
Шаблон соответствует - Немного чище (imho), чтобы в конце просто было всеобщее False.
В последнее время я пытался изучить 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)
Мой экземпляр Arbitrary
для BinaryTree
не самый лучший; это только делает почти сбалансированные деревья. Но я подумал, что это было довольно хорошо. Также обратите внимание, что prop_mirror
проверяет только, когда areMirrorImages
должен возвращать True
; он не раскрывает потенциальных ложных срабатываний (хотя я вполне уверен, что их не будет).
*Main> quickCheck prop_mirror
+++ OK, passed 100 tests.