2012-12-13 11 views
0

두 개의 n-ary 트리가 같은지 확인하기 위해 Haskell에서 간단한 부울 함수를 구현하려고합니다.Haskell에서 두 개의 n-ary 트리가 같은지 확인하십시오.

내 코드는 다음과 같습니다

-- This is the n-ary tree definition. 
-- (I know "Leaf a" is not necessary but I prefer to write it for clarity) 
data Tree a = Leaf a | Node a [Tree a] 
    deriving (Show) 

-- This is a simple tree used for test purposes 
t :: Tree Int 
t = Node 3 [Node 5 [Leaf 11, Leaf 13, Leaf 15], Leaf 7, Leaf 9] 

treeEquals :: Eq a => Tree a -> Tree a -> Bool 
treeEquals (Leaf n1) (Leaf n2) = n1 == n2 
treeEquals (Node n1 xs1) (Node n2 xs2) = n1 == n2 && and(zipWith (treeEquals) xs1 xs2) 
treeEquals _ _ = False 

내 문제는 내가 같은 테스트를 할 경우이다 :

treeEquals t t 
treeEquals t (Leaf 3) 
treeEquals t (Node 3 [Leaf 7]) 

를이 나무가 동일하지 않기 때문에 제대로 false를 반환하지만 테스트를 시도하는 경우

treeEquals t (Node 3 []) 

트리가 동일하므로 true를 반환하기 때문에 작동하지 않습니다.

내가 뭘 잘못하고 있는지 알아?

+0

두 개의 목록 통과를 피하기 위해 zipWith를 사용하지 않고이 방법을 구현하는 더 좋은 방법이 있습니까? – JohnQ

+0

'Leaf'를 이런 식으로 사용하면 중복 표현이됩니다 :'Node x []'vs'Leaf x'. 중복 표현은 일반적으로 정당한 이유 (예 : 일부 작업이 훨씬 빨라지는 경우)에만 사용해야합니다. 이 경우'Leaf' 생성자를 삭제하는 것이 가장 좋은 행동 일 것 같습니다. 또는,'Node' 생성자를'Node a (Tree a) [Tree a]'로 바꿀 수 있습니다. 왜 그럴까요? – dfeuer

답변

1

가 zipWith 전에 다른 & &를 추가하고 목록의 길이가 같은 경우 확인.

+2

이렇게하면 잠재적으로 두 개의 목록 순회를 의미합니다. 처음에는 zipWith를 사용하지 않는 것이 좋습니다. –

+0

@ 다윈, 답변 해 주셔서 감사합니다. 나는 그렇게 생각하지 않았다, 그것은 매우 간단했다! – JohnQ

3

Eq을 유도하고 ==을 사용해야하는 이유는 무엇입니까?

현재 코드의 문제점은 zipWith입니다. 짧은 목록의 끝에 도달하면 즉시 중지되므로 zipWith treeEquals foo []foo과 관계없이 항상 []을 반환합니다.

은 여기 (안된) 다른 솔루션입니다 :

treeEquals :: Eq a => Tree a -> Tree a -> Bool 
treeEquals (Leaf n1) (Leaf n2) = n1 == n2 
treeEquals (Node n1 xs1) (Node n2 xs2) = n1 == n2 && listTreeEquals xs1 xs2 
    where 
    listTreeEquals [] [] = True 
    listTreeEquals (x1 : xs1) (x2 : xs2) = treeEquals x1 x2 && listTreeEquals xs1 xs2 
    listTreeEquals _ _ = False 
treeEquals _ _ = False 
+0

답변 해 주셔서 감사합니다. 예, 저는 무엇이 문제인지 이해했습니다. 불행히도 시험을 위해 스스로 운동해야하기 때문에 스스로 방법을 구현해야합니다. 나는 그들이 나에게 물을 수있는 모든 가능한 것들을 구현하려고 노력하고 있으므로, 단지 ==를 사용할 수는 없다. – JohnQ

+3

@JohnQ 여기서'(==)'에 대한 멋진 점은, 당신이 파생시키지 않아도 구현할지라도'(Node n1 xs1) == (Node n2 xs2) = n1 == n2 && xs1 == xs2' [다른 경우에는 Leaf/Leaf'와'_/_']에 대한 방정식을 더한 것입니다. 그런 다음,'xs1 == xs2'는 일반적인'instance Eq a => Eq [a]'를 사용하여 올바른 일을합니다. 'treeEquals'의 경우 간단히'treeEquals = (==)';)를 사용할 수 있습니다. –

관련 문제