2011-12-27 3 views
1

파서가 더 나은 오류 메시지를 생성해야하기 때문에 attoparsec에서 Parsec으로 일부 코드를 변환 중입니다. attoparsec 코드는 inClass (및 notInClass)을 광범위하게 사용합니다. Parsec에서 기계식으로 inClass -occurences를 번역 할 수있는 유사한 기능이 있습니까? Hayoo와 Hoogle은이 문제에 대한 통찰력을 제공하지 않았습니다.파섹의 'inClass`에 해당하는 attoparsecs

inClass :: String -> Char -> Bool 

inClass "a-c'-)0-3-"\ x -> elem x "abc'()0123-"는 동등하지만, 후자는 넓은 범위에 대해 작성하는 비효율적 지루하다.

사용할 수있는 것이 없다면 직접 함수를 다시 구현합니다.

답변

1

그러한 결합 자 (combinator)가 없습니다. 존재했다면, (이는 모든 표준 파서 결합 자 함수가 정의 된 Char이 정의되어 있음)에 있습니다. 당신은 그것을 아주 쉽게 정의 할 수 있어야합니다.

비록 attoparsec이 its implementation과 동일한 성능 이점을 얻을 수 있다고 생각하지 않습니다. 8 비트 문자로만 작동하는 내부 FastSet 유형을 사용합니다. 물론 유니 코드 지원이 필요하지 않은 경우 문제가되지 않을 수도 있지만 code for FastSet'\255'보다 큰 Chars를 전달하면 예기치 않은 결과를 얻게되므로 FastSet 기반 솔루션을 다시 사용하면 최소한 구문 분석중인 문자열을 binary mode에서 읽어야합니다.

: 당신의 범위 문자열이 짧은 경우,이 같은 간단한 해결책은 꽤 빨리 될 가능성이

(이 수출 아니에요로서 당신은 또한 ..., 당신의 프로그램에 FastSet의 구현을 복사해야합니다)

type Range = (Char, Char) 

inClass :: String -> Char -> Bool 
inClass = inClass' . parseClass 

parseClass :: String -> [Range] 
parseClass "" = [] 
parseClass (a:'-':b:xs) = (a, b) : parseClass xs 
parseClass (x:xs) = (x, x) : parseClass xs 

inClass' :: [Range] -> Char -> Bool 
inClass' cls c = any (\(a,b) -> c >= a && c <= b) cls 

당신은 (단일 inClass s 많은 호출이 이루어지는 경우를 포함) 위의 버전으로 적어도 효율적으로해야한다 이런 식으로 뭔가를 시도하고 추가로리스트 탐색 오버 헤드를 피할 수 :

inClass :: String -> Char -> Bool 
inClass "" = const False 
inClass (a:'-':b:xs) = \c -> (c >= a && c <= b) || f c where f = inClass xs 
inClass (x:xs) = \c -> c == x || f c where f = inClass xs 

(람다의 으로 재전송하는 데주의하십시오. GHC가이 일을 할 수 있는지/모르겠다.)

+0

이 질문은 실제로 해결책을 요구하지는 않았지만 아마도 TH 매크로를 작성하게 될 것이지만 위의 코드는 문제를 해결합니다. 아주 잘. – dflemstr

+0

나는 "nope, sorry"가 미래의 방문자들에게는별로 도움이되지 않기 때문에 효율적인 구현이 간다면 가치를 추가 할 것이라고 생각했습니다. :) – ehird

1

아니요, parsec에는 해당 항목이 없습니다. 직접 작성해야합니다. I는 두 가지 옵션

  1. 는 전자가이다 satisfy

전달할 파싱하는 기능을 만들 oneOf

  • 으로 사용, 그것에서 String을 만들 inClass 구문 분석 참조 물론 후자에 대한 특별한 경우가 있습니다. 수업 시간이 길어지면 효율성이 떨어집니다. 그러나 구현하기가 좀 더 쉬울 것입니다.

    (|||) :: (a -> Bool) -> (a -> Bool) -> a -> Bool 
    p ||| q = \x -> p x || q x 
    (&&&) :: (a -> Bool) -> (a -> Bool) -> a -> Bool 
    p &&& q = \x -> p x && q x 
    
    parseClass (l:'-':h:more) = ((>= l) &&& (<= h)) ||| parseClass more 
    parseClass (c:cs) = (== c) ||| parseClass cs 
    parseClass [] = const False 
    

    은 간단합니다.