私はまだ Haskell と関数型プログラミング全般にかなり慣れていないので、基本的な概念を学習する手段として、JSON を解析し、きれいに出力する Parsec を使用した小さなプログラムを作成しています。これは私がこれまでに持っているものです:
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 = do
str <- between (char '"') (char '"') (many (noneOf "\""))
return . JString $ str
parseJNumber = do
num <- many digit
return . JNumber . read $ num
parseJBool = do
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
今のところ、数値は整数であると想定しています。個別parseJString
にparseJNumber
、、、、parseJBool
およびparseJNull
ghci で期待どおりに動作します。さらに、parseJValue
文字列と数値を正しく解析します。
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
true
ただし、 、false
、またはを解析しようとすると失敗し、null
興味深いエラーが発生します。
ghci> parse parseJValue "test" "true"
Right (JNumber *** Exception: Prelude.read: no parse
解析は成功しましたが、解析はJNumber
Prelude.read が失敗したことを示すエラーが続きます。パーサーを構築する際の中心的な概念が欠けているように感じますが、どこが間違っているのかわかりません。また、自分のコードで初歩的な間違いを犯していますか?つまり、これは「悪い」haskell と見なされますか?