2014-11-17 3 views
-1

다른 rigid 타입 에러 에러 질문에 대한 많은 답을 조사했습니다; 그러나 아, 내 지식에 대한 그들 중 누구도 내 경우에 적용되지 않습니다. 그래서 나는 또 다른 질문을 할 것이다.또 다른 하스켈 리지드 타입 변수 에러

module MultipartMIMEParser where 

import Control.Applicative ((<$>), (<*>), (<*)) 
import Text.ParserCombinators.Parsec hiding (Line) 

data Header = Header { hName :: String 
        , hValue :: String 
        , hAddl :: [(String,String)] } deriving (Eq, Show) 

data Content a = Content a | Posts [Post a] deriving (Eq, Show) 

data Post a = Post { pHeaders :: [Header] 
        , pContent :: [Content a] } deriving (Eq, Show) 

post :: Parser (Post a) 
post = do 
    hs <- headers 
    c <- case boundary hs of 
      "" -> content >>= \s->return [s] 
      b -> newline >> (string b) >> newline >> 
       manyTill content (string b) 
    return $ Post { pHeaders=hs, pContent=c } 

boundary hs = case lookup "boundary" $ concatMap hAddl hs of 
       Just b -> "--" ++ b 
       Nothing -> "" 
     -- TODO: lookup "boundary" needs to be case-insensitive. 

content :: Parser (Content a) 
content = do 
    xs <- manyTill line blankField 
    return $ Content $ unlines xs -- N.b. This is the line the error message refers to. 
    where line = manyTill anyChar newline 

headers :: Parser [Header] 
headers = manyTill header blankField 

blankField = newline 

header :: Parser Header 
header = 
    Header <$> fieldName <* string ":" 
      <*> fieldValue <* optional (try newline) 
      <*> nameValuePairs 
    where fieldName = many $ noneOf ":" 
     fieldValue = spaces >> many (noneOf "\r\n;") 
     nameValuePairs = option [] $ many nameValuePair 

nameValuePair :: Parser (String,String) 
nameValuePair = do 
    try $ do n <- name 
      v <- value 
      return $ (n,v) 

name :: Parser String 
name = string ";" >> spaces >> many (noneOf "=") 

value :: Parser String 
value = string "=" >> between quote quote (many (noneOf "\r\n;\"")) 
    where quote = string "\"" 

그리고 오류 메시지 :

가 여기에 관련 코드의

내가 본 바로는
Couldn't match type `a' with `String' 
    `a' is a rigid type variable bound by 
     the type signature for content :: Parser (Content a) 
     at MultipartMIMEParser.hs:(See comment in code.) 
Expected type: Text.Parsec.Prim.ParsecT 
       String() Data.Functor.Identity.Identity (Content a) 
    Actual type: Text.Parsec.Prim.ParsecT 
       String() Data.Functor.Identity.Identity (Content String) 
Relevant bindings include 
    content :: Parser (Content a) 
    (bound at MultipartMIMEParser.hs:72:1) 
In a stmt of a 'do' block: return $ Content $ unlines xs 
In the expression: 
    do { xs <- manyTill line blankField; 
     return $ Content $ unlines xs } 
In an equation for `content': 
    content 
     = do { xs <- manyTill line blankField; 
      return $ Content $ unlines xs } 
     where 
      line = manyTill anyChar newline 

, 문제는 내가 명시 적으로 unlines xs를 사용하여 String를 반환하고있어 것입니다 형식 서명에 a의 일반 특성이 적용되지 않습니다. 나는 이해에 가깝습니까?

아마도이 파서가 String 이외의 다른 유형에 사용되기 때문에 을 generic으로 선언했습니다. 아마도 저는 조기에 추상화하고 있습니다. 내 모든 a을 제거하려고했지만, 더 많은 컴파일 오류가 발생하기 시작했습니다. 이 시점에서 합리적이라면 제네릭 방식을 고수하고 싶습니다.

코드에서 내가 뭘 하려는지 분명합니까? 그렇다면 최선의 방법에 대한 제안 사항이 있습니까? , 여기 당신이 String ~ a있을 것

+0

어떤 줄이 오류입니까? SSCCE를 만들 수 있습니까? – Shoe

+0

코드에서 오류가있는 행을 주석으로 기록했습니다. 실제 모듈에서 71:12 줄입니다. 그러나 모든 코드를 포함하지 않았으므로 여기서는 쓸모가 없습니다. 그 줄은'content $ '에'return $ Content $ unlines xs'입니다. –

+0

SSCCE는 어떻습니까? – Shoe

답변

4

당신은 contentParser (Content a) 입력이 컴파일러를 이야기하고 있지만 오류의 원인이 라인은

return $ Content $ unlines xs 

unlines 이후 리턴한다 String이며, Content 생성자는 a -> Content a을 입력있다 Content $ unlines xs 값은 Content String입니다. content의 형식 서명을 Parser (Content String)으로 변경하면 컴파일해야합니다. 아마도,이 파서 결국 문자열 이외의 다른 유형에 사용될 수 있기 때문


이 나는 ​​일반적인 될 컨텐츠 선언했습니다. 아마도 저는 조기에 추상화하고 있습니다. 나는 모든 것을 제거하려고 시도했지만 더 많은 컴파일 오류가 발생하기 시작했습니다. 이 시점에서 합리적이라면 제네릭 방식을 고수하고 싶습니다.

그것은 일반적으로 Content를 선언 괜찮습니다, 많은 경우에이 문제를 해결하기 위해 정확한 올바른 방법입니다, 문제는 컨테이너가 일반적인 반면, 때마다 뭔가 콘크리트로 컨테이너를 채울 즉, 유형 변수도 구체적이어야합니다. 특히 :

> :t Container (1 :: Int) 
Container 1 :: Container Int 
> :t Container "test" 
Container "test" :: Container String 
> :t Container (Container "test") 
Container (Container "test") :: Container (Container String) 

모든 유형 변수는 유형 변수없이 유추됩니다. 컨테이너를 사용하여 원하는 것을 담을 수 있으며 컴파일러에게 무엇이 정확한지 정확하게 알려주고 있는지 확인해야합니다.

+0

위대한 답변! 화제를 elucidating 주셔서 감사합니다! –

+0

유형이 변경 될 수 있음을 나타내려면 ghc 7.10.1 [부분 형식 서명] (https://ghc.haskell.org/trac/ghc/wiki/PartialTypeSignatures) 기능이 유용 할 것입니다. 물론 7.10.1은 아직 나오지 않았지만 명심해야 할 것이있다. – Cubic

+0

@Cubic 나는이 확장을 아직 보지 못했다. 이것이 내가 7.10을 더 원하게 만든다! – bheklilr