2017-01-15 2 views
2

여기에 코드입니다 : 현재 코드, runParser (some item) "abcd" 루프와왜 이것이 '데이터'로 반복되지만 'newtype'로 반복되지 않습니까?

import Control.Applicative 

-- newtype Parser a = Parser { runParser :: String -> [(a, String)] } 
data Parser a = Parser { runParser :: String -> [(a, String)] } 

instance Functor Parser where 
    fmap f (Parser p) = Parser (\s -> [(f x, s') | (x, s') <- p s ]) 

instance Applicative Parser where 
    pure a = Parser (\s -> [(a, s)]) 
    Parser q <*> Parser p = Parser (\s -> [(f x, s'') | (f, s') <- q s, (x, s'') <- p s']) 

instance Alternative Parser where 
    empty = Parser (\s -> []) 
    Parser q <|> Parser p = Parser (\s -> q s ++ p s) 

item = Parser (\s -> case s of 
        (x:xs) -> [(x, xs)] 
        _ -> [] 
      ) 

하지만, 파서는 newtype로 선언 된 경우, 그냥 잘 작동합니다.

+1

정확히 무엇을 너는 묻고 있니? 당신이 보여줄 수있는 모범이 있습니까? – Alec

+0

이 질문에는 거의 정보가 없습니다. 더 자세한 정보를 공유하지 않으면 어떤 일이 벌어지고 있는지 추측 할 수 없습니다. [MCVE] (http://stackoverflow.com/help/mcve)를 제공해야합니다. – chi

답변

6

the difference between data and newtype 중 하나에 도달하는 좋은 방법입니다. 여기에서 문제의 핵심은 실제로 <|> 정의의 패턴 일치에 있습니다.

런타임에 newtype은 포장중인 유형과 동일하게됩니다. 그런 다음 newtype이 패턴 일치 인 경우 GHC는 아무 것도하지 않습니다. WNHF로 평가할 생성자가 없습니다.

반대로 data이 일치하면 Parser q 패턴을 보면 GHC가 해당 파서를 WNHF로 평가해야한다고 알립니다. 이는 some<|>의 무한대이므로 문제입니다. 문제를 해결하는 방법은 두 가지가 data에 있습니다

  • <|>에서 Parser 패턴하지 마십시오

    instance Alternative Parser where 
        empty = Parser (\s -> []) 
        q <|> p = Parser (\s -> runParser q s ++ runParser p s) 
    
  • 사용 lazy patterns :

    instance Alternative Parser where 
        empty = Parser (\s -> []) 
        ~(Parser q) <|> ~(Parser p) = Parser (\s -> q s ++ p s) 
    
+1

'<|>'이 왼쪽 편향되기 때문에 첫 번째 엄격한 패턴이 좋습니다. 그래서 이것은'Parser q <|> ~ (Parser p) = ...'라고 쓸 수 있습니다. 하지만이 경우 가장 좋은 해결책은'newtype'을 사용하는 것입니다! – dfeuer

+0

고마워요, 그게 많이 도움이됩니다. 나는 여전히 WNHF로 평가되는 '데이터'와 '<|>'에 관한 문제 사이의 관계를 이해하지 못한다. – Procrade

관련 문제