2016-12-15 6 views
0

この小さなJSONパーサをゼロから構築していて、なんらかの理由で解析するオブジェクトを取得できません。 コード:Haskell JSONパーサーがオブジェクトを解析していない

import Data.Char 
import Control.Monad 
import Control.Applicative 
import Control.Monad (liftM, ap) 

newtype Parser a = Parser (String -> [(String, a)]) 

parse :: Parser a -> (String -> [(String, a)]) 
parse (Parser p) = p 

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

failure :: Parser a 
failure = Parser (\ts -> []) 

produce :: a -> Parser a         --parse (item >>= produce) "hello" 
produce x = Parser (\ts -> [(ts, x)]) 

instance Applicative Parser where 
    pure x = produce x 
    Parser pf <*> Parser px = Parser (\ts -> [ (ts'', f x)| (ts', f) <- pf ts, 
                  (ts'', x) <- px ts']) 

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

instance Monad Parser where 
    --return :: a -> Parser a 
    return = produce 
    --(>>=) :: Parser a -> (a -> Parser b) -> Parser b 
    (Parser px) >>= f = Parser (\ts -> 
     concat [parse (f x) ts' | (ts', x) <- px ts]) 

satisfy :: (Char -> Bool) -> Parser Char 
satisfy p = item >>= (\c -> 
    if p c then 
    produce c 
    else failure) 

char :: Char -> Parser Char 
char c = satisfy (c ==) 

string :: String -> Parser String      --parse (string "hello") "hello" 
string [] = produce [] 
string (c:cs) = char c >>= (\c' -> 
       string cs >>= (\cs' -> 
       produce (c:cs))) 

instance Alternative Parser where 
    empty = failure 
    (<|>) = orElse 
    many p = some p <|> produce [] 
    some p = (:) <$> p <*> many p 

orElse :: Parser a -> Parser a -> Parser a 
orElse (Parser px) (Parser py) = Parser (\ts -> 
    case px ts of 
     [] -> py ts 
     xs -> xs) 


---------------Parsec bits--------------------------- 

oneOf :: [Char] -> Parser Char 
oneOf s = satisfy (flip elem s) 

noneOf :: [Char] -> Parser Char 
noneOf cs = satisfy (\c -> not (elem c cs)) 

sepBy :: Parser a -> Parser String -> Parser [a] 
sepBy p sep   = sepBy1 p sep <|> return [] 

sepBy1 :: Parser a -> Parser String -> Parser [a] 
sepBy1 p sep  = do{ x <- p 
         ; xs <- many (sep >> p) 
         ; return (x:xs) 
         } 

------------------------------------------------------- 

data Value = StrJson String 
      | IntJson Int 
      | BoolJson Bool 
      | ObjectJson [Pair] 
      | ArrayJson [Value] 
      | NullJson 
       deriving (Eq, Ord, Show) 

type Pair = (String, Value) 

type NullJson = String 

tok :: String -> Parser String 
tok t = string t <* whitespace 

whitespace :: Parser() 
whitespace = many (oneOf " \t") *> pure() 

var :: Parser Char 
var = oneOf ['A' .. 'Z'] <* whitespace 


val :: Parser Value 
val = IntJson <$> jIntParser 
    <|> NullJson <$ tok "null" 
    <|> BoolJson <$> jBoolParser 
    <|> StrJson <$> jStrParser 
    <|> ArrayJson <$> jArrParser 
    <|> ObjectJson <$> jObjParser 


jStrParser :: Parser String 
jStrParser = some (noneOf ("\n\r\"=[]{},")) <* whitespace 

jIntParser :: Parser Int 
jIntParser = (some (oneOf ['0' .. '9']) >>= produce . read) <* whitespace 

jBoolParser :: Parser Bool 
jBoolParser = ((string "False" *> produce False) <|> (string "True" *> produce True)) 

jObjParser :: Parser [Pair] 
jObjParser = do 
    char '{' 
    jp <- jPairParser `sepBy1` (tok ",") 
    char '}' 
    produce jp 

jPairParser :: Parser (String, Value) 
jPairParser = do 
     jStr <- jStrParser 
     tok ":" 
     jVal <- val 
     produce (jStr, jVal) 


jArrParser :: Parser [Value] 
jArrParser = do 
    char '[' 
    jArr <- val `sepBy1` (tok ",") 
    char ']' 
    produce jArr 

私は「jObjParserを解析する 『{ASD:ASD}と私のパーサを実行すると』」それは失敗し、私はさらに行くときとで実行「jPairParserを解析する 『ASD:ASD』」それはまた、意志失敗します。だから、私はペアパーサーが問題だと思うが、私はなぜうまくいかない。私はおそらくちょうど愚かであるので、どんな助けも非常に感謝されるでしょう、事前に感謝します。

答えて

2

まず最初に、サンプルコードの多くの関数が、特定のニーズに応じて、parsec、attoparsec、trifectaなどの多くのパーサーコンビネータパッケージですでに利用可能であることを指摘しておきます。 Aesonなどについては言うまでもない。しかし、それはあまり答えではないので、私はあなたが一種のコーディング・エクササイズをしていると想定し、それらを意図的に使用していないと仮定します。ここ

jStrParser :: Parser String 
jStrParser = some (noneOf ("\n\r\"=[]{},")) <* whitespace 

そして:あなたのコードを一瞥することにより

私の最高の推測では、問題がここにあるということである

jPairParser :: Parser (String, Value) 
jPairParser = do 
     jStr <- jStrParser 
     tok ":" 
     jVal <- val 
     produce (jStr, jVal) 

jStrParserは貪欲であり、それは":"て食べるようになります。 ":"が既に消費されているため、jPairParsertok ":"で失敗します。

+0

うん、私は、助けのための感謝をこのようなものをより良く把握を試み、取得する目的でそれらを避けました。 – Bort

2

基本的に問題はjStrParserです。それは"asd:asd"を受け入れます。しかし間違っている。第2に、jStrParserは、'"'で始まり、'"'で終わる文字列だけを受け入れる必要があるため、正しくありません。

だから、あなたは次のように修正することができます。

readS_to_Parser :: ReadS a -> Parser a 
readS_to_Parser r = Parser (map swap . r) 

jStrParser = readS_to_Parser reads <* whitespace  
+0

そのコードは私にとってはうまくいかないようですが、jStrParserは文字列入力に失敗します。 – Bort

+0

これは '' \ "foo \" "' 'foo" ' – freestyle

+0

私の悪い、ありがとうございます。 – Bort

関連する問題