2014-06-12 2 views
2

문자열을 비교하는 함수를 만들었습니다. 물론 이것은 배울 수있는 연습이며 가장 현대적인 언어의 문자열을 사용하는 < 연산자를 잘 알고 있습니다.). 재귀를 수행하기 위해 함수에 패턴 매칭을 사용하고 있지만, 실제로 어떤 일이 일어나고 있는지 확실하지 않습니다. 여기 내 코드는 다음과 같습니다여러 경우를 포함하는 패턴 일치

compareStrings :: String -> String -> Char 
compareStrings (x:xs) (y:ys) 
    | x > y = '>' 
    | x < y = '<' 
    | x == y = compareStrings xs ys 
compareStrings [a] [b] 
    | a < b = '<' 
    | a > b = '>' 
    | a == b = '=' 

그래서, 경우에 나는 하나 개의 빈 목록과 싱글 목록 및 빈 목록과 일반 목록 (여러 요소)처럼, 내 코드 취재 아니에요 많이 있습니다. 그리고 물론 그 대칭 대응. 어떻게 모두 확인했는지 확인할 수 있습니까? 후드 아래에 뭔가가 있거나 그냥 문자열 (내 의도였던 문자가 아닌)을 어느 시점에서 비교하는 것인가? 나는 그것을 인식하지 못하고 있습니까?

  • 요약하면 다음과 같습니다. 내 코드에서 발생할 수있는 모든 사례를 다루고 있으며 그렇지 않은 경우 어떻게 확인할 수 있습니까? 그리고 두 개의 서로 다른 패턴을 선언하지 않고 대칭의 경우를 처리하는 방법 (첫 번째 목록은 비어 있지만 두 번째 것은 아니고 다른 방법은 둥근 것처럼)을 처리하는 방법은 무엇입니까?
+0

싱글 톤의 경우 중복되어 두 개의 빈 목록을 비교해도 충분합니다 (항상 같음). 일단 그렇게하면 다른 두 가지 사례 만 남게됩니다. –

+0

대칭의 경우 대개의 경우 대소 문자를 적어 둡니다. 이건 약간 짜증나지만 실제로는 너무 많지는 않습니다. –

답변

6

이와 같은 문제는 각 목록의 첫 번째 요소에만 관심이 있으며 목록이 비어있는 경우에만 발생합니다. 일반적으로 전달할 수있는 모든 종류의 목록을 다룰 때까지 함수가 작동중인 목록의 요소를 결정한 다음 사례를 처리해야합니다.

이 인스턴스의 경우 두리스트 모두 데이터 (x:xs)(y:ys)을 가지며, 둘 중 하나 또는 둘 다 비어있는 경우. 당신은 데이터 목록이 실제로 데이터를 가지고는 첫번째 패턴이 전달되는 경우 이후 중간 이가지 경우에, 우리는 지정하지 않았다

-- Both are empty 
compareStrings [] [] = '=' 
-- The first is empty, the second is not 
compareStrings [] ys = '<' 
-- The first is not empty, the second is 
compareStrings xs [] = '>' 
-- Both have data 
compareStrings (x:xs) (y:ys) = <your current implementation> 

참고로이 문제를 커버 할 수있다, 다음 모두는 없었다 빈. not (xs == [] && ys == []) && (xs == [] && ys == _) (코드가 아니기 때문에 실행하지 마십시오) 인 경우 ys[]이 아닙니다. 또한 xs == [x] && ys == [y]의 사례를 확인하지 않아도되었으므로 [x] == x:[]은 이고 x == z[] == zs과 일치합니다.

실제로 모든 패턴을 다루는 지 확인하려면 @StephenDiehl이 제안한대로 -fwarn-non-exhaustive-patterns을 사용하도록 설정해야합니다.

+0

설명 주셔서 대단히 감사합니다! 매우 도움이되었습니다. – Setzer22

+2

@ Setzer22' '='',' '<'' and ''>''을 반환 값으로 사용하는 대신 권하는'Ordering' 데이터 형식을 사용하는 것이 좋습니다 :'data Ordering = LT | EQ | GT '를 사용하기 때문에 타입 서명을'String -> String -> Ordering'으로 변경하고''<''를'LT ',''= ''를'EQ' 및'>> GT'. 'Ordering'은 그 세 가지 값 중 하나 일 뿐이니까, 망칠 수는 없습니다! – bheklilr

+0

@ Setzer22 내가 생각했던 흥미있는 대안 구현은 항상'EQ'가 아닌'Ordering'의'Monoid' 인스턴스를 사용하는 것입니다,'LT <> EQ == LT','GT <> EQ == GT','EQ <> EQ == EQ' (그리고이 경우에는'<>'는 교환 가능합니다.) 때문에이 함수를'compareStrings xs ys = mconcat $ zipWith compare xs ys'로 작성하면됩니다. 'Data.Composition'을 임포트했다면,'compareStrings = mconcat. : zipWith compare'와 같이 포인트를 쓰지 않아도됩니다. – bheklilr

5

오전 내 코드로 발생할 수있는 모든 경우를 커버하고,이 경우가 아니라면, 어떻게 확인 할 수?

실제로이 패턴 일치는 일부 입력에 대해서는 철저하지 않습니다. 당신은 GHC에게 깃발 -fwarn-non-exhaustive-patterns을 가지고 이것을 경고하도록 말할 수 있으며, 커버하지 않은 경우를 출력 할 것입니다.

cover.hs:2:1: Warning: 
    Pattern match(es) are non-exhaustive 
    In an equation for `compareStrings': 
     Patterns not matched: 
      [] _ 
      (_ : (_ : _)) [] 
      (_ : (_ : _)) (_ : _) 
      [_] [] 
      ... 
+0

감사합니다.이 컴파일러 경고는 꼭 사용해야하는 것 같아서 도움이 될 것입니다. – Setzer22

+0

일반적으로 나는 단지'-Wall'을 사용하여 컴파일하고 일부 경고를 선택적으로 끌 수 있습니다. –