2011-09-15 3 views
6

약 한 달 동안 하스켈과 게임을 해왔습니다. 내 첫 "진짜"하스켈 프로젝트에서 나는 품사 태그 작성기를 쓰고있다. 나는했습니다 표준화 된 품사 태그의 긴 목록을 위

data Tag = CC | CD | DT | EX | FW | IN | JJ | JJR | JJS ... 

입니다 다음과 같이이 프로젝트의 일환으로 나는 구현하는 품사 태그를 나타냅니다 Tag라는 유형이 의도적으로 잘 렸습니다. 그러나이 표준 태그 세트에는 $ (PRP $ 및 NNP $)로 끝나는 두 개의 태그가 있습니다. 이름에 $가있는 유형 생성자를 사용할 수 없으므로 이름을 PRPS 및 NNPS로 변경했습니다.

이 모든 것이 훌륭하지만 어휘집의 문자열에서 태그를 읽고 내 Tag 유형으로 변환하고 싶습니다. 이 시도는 실패합니다 :

instance Read Tag where 
    readsPrec _ input = 
     (\inp -> [((NNPS), rest) | ("NNP$", rest) <- lex inp]) input 

$에있는 하스켈 렉서 초크. 이 아이디어를 풀어내는 방법은 무엇입니까?

쇼 구현은 매우 간단했습니다. 읽기와 비슷한 전략이 있다면 좋을 것입니다.

instance Show Tag where 
    showsPrec _ NNPS = showString "NNP$" 
    showsPrec _ PRPS = showString "PRP$" 
    showsPrec _ tag = shows tag 
+2

자동으로 파생 된 인스턴스를 사용하는 대신 자신 만의'Show' 및'Read' 인스턴스를 작성해야 할 때가 거의 없습니다. 데이터 유형이 내부 표현 (예 :'Data.Set.Set 'and such,'fromList' 호출을 내뱉습니다) 또는 리터럴로 작동합니다. 'Num'의 인스턴스는 정수 리터럴을 출력합니다. –

답변

5

여기에 Read을 악용하는 것입니다.

ShowRead는 디버깅을 사용하려면 유효한 하스켈 값을 인쇄하고 분석하기위한 것입니다 등이하지 않습니다 항상 완벽하게 (예를 들어, 당신은 fromList ISN하려면 Map 값에 전화를 show를 호출 한 후 자격을 갖춘 Data.Map과를 가져 오는 경우 '자격이 없음')하지만 유효한 출발점입니다.

일부 특정 형식과 일치하도록 값을 인쇄하거나 구문 분석하려면 후자에 대한 예쁘기 인쇄 라이브러리와 실제 구문 분석 라이브러리 (예 : uu-parsinglib, polyparse, parsec 등)를 사용하십시오 . 그들은 일반적으로 ReadS보다 구문 분석을 훨씬 잘 지원합니다 (GHC의 ReadP이 아님).

당신은 이것이 필요하지 않다고 주장 할 수 있지만, 이것은 당신이하고있는 quick'n'dirty 해킹 일뿐입니다. 더러운 해킹은 주변에 머물러있는 경향이 있습니다. 처음에는 올바르게 처리하십시오. 나중에 제대로 "제대로"수행하기를 원하면 다시 작성하는 것이 적다는 것을 의미합니다.

+0

답변 해 주셔서 감사합니다. 그리고 여기서는 이것이 적절한 방법이라고 생각했습니다. 그렇지 않으면 읽기 파서를 전혀 사용하지 않았을 것입니다 (어휘의 행은 표준'words' 함수를 사용하여 멋지게 형식화되고 분리됩니다)! OOP에서 왔으므로 필자는 필자가 필요로하는 동작을 구현하기 위해 구현해야하는 인터페이스로서 여전히 타입 클립을 생각하고있다. – svoisen

+0

특히,'Read'와'Show'는 가난한 사람의 직렬화/역 직렬화를'String'과주고 받기위한 것입니다. 직렬화 된 형식을 잘라내어 원본 소스 파일에 붙여 넣으면 'show'가 적용된 것과 같은 값을 나타냅니다. –

4

그런 다음 하스켈 렉서를 사용하지 마십시오. read 함수는 ParSec을 사용합니다.이 함수는 Real World Haskell 책에 대한 훌륭한 소개를 제공합니다.

여기
import Text.Read 
import Text.ParserCombinators.ReadP hiding (choice) 
import Text.ParserCombinators.ReadPrec hiding (choice) 

data Tag = CC | CD | DT | EX | FW | IN | JJ | JJR | JJS deriving (Show) 

strValMap = map (\(x, y) -> lift $ string x >> return y) 

instance Read Tag where 
    readPrec = choice $ strValMap [ 
     ("CC", CC), 
     ("CD", CD), 
     ("JJ$", JJS) 
     ] 

그냥

(read "JJ$") :: Tag 

코드는 꽤 자기 설명입니다 그것을 실행 작동하는 것 같다 몇 가지 코드입니다. string x 파서 모나드는 x과 일치하고 성공하면 (예외는 발생하지 않음) y이 반환됩니다. 우리는 choice을 사용하여이 모든 것을 선택합니다. 그러면 적절하게 되돌아갑니다. 따라서 CCC 생성자를 추가하면 CC 부분 일치하는 "CCC"가 나중에 실패하고 CCC으로 되돌아갑니다. 물론 필요하지 않은 경우 <|> 연결자를 사용하십시오.

+0

감사합니다. 이것은 내가 성취하려고 시도했던 것입니다. – svoisen

+1

@ gatoatigrado : 사실,'Read' 함수는 parsec을 사용하지 않습니다 ** : 그들은 자신의 파서를 가지고 있습니다. – ivanm

관련 문제