haskell - Json parser, incorrectly parsing string as a number -


i'm still pretty new haskell , functional programming in general, i'm writing small program parsec parse json , pretty print means of learning basic concepts. have far:

import text.parsec import text.parsec.string  data jvalue = jstring string             | jnumber double             | jbool bool             | jnull             | jobject [(string, jvalue)]             | jarray [jvalue]               deriving (eq, ord, show)  parsejstring, parsejnumber, parsejbool, parsejnull :: parser jvalue parsejstring =     str <- between (char '"') (char '"') (many (noneof "\""))     return . jstring $ str  parsejnumber =     num <- many digit     return . jnumber . read $ num  parsejbool =     val <- string "true" <|> string "false"     case val of         "true"  -> return (jbool true)         "false" -> return (jbool false)  parsejnull = string "null" >> return jnull  parsejvalue :: parser jvalue parsejvalue =   parsejstring              <|> parsejnumber              <|> parsejbool              <|> parsejnull 

for now, i'm assuming numbers integers. individually, parsejstring, parsejnumber, parsejbool, , parsejnull work expected in ghci. additionally, parsejvalue correctly parses strings , numbers.

ghci> parse parsejstring "test" "\"test input\"" right (jstring "test input") ghci> parse parsejnumber "test" "345" right (jnumber 345.0) ghci> parse parsejbool "test" "true" right (jbool true) ghci> parse parsejnull "test" "null" right jnull ghci> parse parsejvalue "test" "\"jvalue test\"" right (jstring "jvalue test") ghci> parse parsejvalue "test" "789" right (jnumber 789.0) 

parsejvalue fails, however, when try parse true, false, or null, , interesting error.

ghci> parse parsejvalue "test" "true" right (jnumber *** exception: prelude.read: no parse 

i successful parse, parse returns jnumber followed error stating prelude.read failed. feel i'm missing core concept in building parsers, can't see i've gone wrong. also, making beginner mistakes code, i.e. of considered "bad" haskell?

the problem usage of many in parsejnumber. valid parse, when no character of following string consumed ("many p applies parser p 0 or more times. [...]"). need many1:

parsejnumber =   num <- many1 (oneof "0123456789")   return $ jnumber (read num :: double) 

edit:

somehow, think combination of (.) , ($) looks kind of weird. use (.) when can rid of function parameter (like in usage of (>>=)) , ($) when i'm lazy write parentheses. in function parsejstring not need (.) in order right binding precedences. (i did same transformation in code above.)

parsejstring =   str <- between (char '"') (char '"') (many (noneof "\""))   return $ jstring str 

additionally, eliminate code-repetition refactoring parsejbool:

parsejbool =   val <- string "true" <|> string "false"   return (case val of     "true"  -> jbool true     "false" -> jbool false) 

i rewrite case-construct (total) local function:

parsejbool = (string "true" <|> string "false") >>= return . tojbool    -- there 2 possible strings pattern match   tojbool "true" = jbool true   tojbool _      = jbool false 

last not least, can transform other functions use (>>=) instead of do-blocks.

-- additionally, not need type signature `read` -- constructor `jnumber` infers correct type parsejnumber =   many1 (oneof "0123456789") >>= return . jnumber . read  parsejstring =   between (char '"') (char '"') (many (noneof "\"")) >>= return . jstring 

Comments

Popular posts from this blog

javascript - DIV "hiding" when changing dropdown value -

Does Firefox offer AppleScript support to get URL of windows? -

android - How to install packaged app on Firefox for mobile? -