HaskellでChemistryやBiology関連のParser書きたいなぁと思っているのでParsecをきちんと使えるようになりたい。
16章にJSONのParserを書く例が載っていたのでやってみた。写経しててみて、Parserとデータコンストラクタというかデータ定義はセットなのかな?と思ったんだけどどうなんだろう?
Hackageに参考になりそうなパッケージないか、あとで探す。
{-# LANGUAGE FlexibleInstances,TypeSynonymInstances #-} import JSONClass import Numeric import Control.Applicative import Control.Monad (MonadPlus(..), ap) import Text.ParserCombinators.Parsec hiding (many, optional, (<|>)) p_text :: CharParser () JValue p_text = spaces *> text <?> "JSON text" where text = JObject <$> p_object <|> JArray <$> p_array p_series :: Char -> CharParser () a -> Char -> CharParser () [a] p_series left parser right = between (char left <* spaces) (char right) $ (parser <* spaces) `sepBy` (char ',' <* spaces) p_array :: CharParser () (JAry JValue) p_array = JAry <$> p_series '[' p_value ']' p_object :: CharParser () (JObj JValue) p_object = JObj <$> p_series '{' p_field '}' where p_field = (,) <$> (p_string <* char ':' <* spaces) <*> p_value p_value :: CharParser () JValue p_value = value <* spaces where value = JString <$> p_string <|> JNumber <$> p_number <|> JObject <$> p_object <|> JArray <$> p_array <|> JBool <$> p_bool <|> JNull <$ string "null" <?> "JSON value" p_bool :: CharParser () Bool p_bool = True <$ string "true" <|> False <$ string "false" p_value_choice = value <* spaces where value = choice [ JString <$> p_string , JNumber <$> p_number , JObject <$> p_object , JArray <$> p_array , JBool <$> p_bool , JNull <$ string "null" ] <?> "JSON value" p_number :: CharParser () Double p_number = do s <- getInput case readSigned readFloat s of [(n, s')] -> n <$ setInput s' _ -> empty p_string :: CharParser () String p_string = between (char '\"') (char '\"') (many jchar) where jchar = char '\\' *> (p_escape <|> p_unicode) <|> satisfy (`notElem` "\"\\") p_escape = choice (zipWith decode "bnfrt\\\"/" "\b\n\f\r\t\\\"/") where decode c r = r <$ char c p_unicode :: CharParser () Char p_unicode = char 'u' *> (decode <$> count 4 hexDigit) where decode x = toEnum code where ((code,_):_) = readHex x
動かす
*Main> parse p_text "(unknown)" "[1,2,3]" Right (JArray (JAry {fromJAry = [JNumber 1.0,JNumber 2.0,JNumber 3.0]})) *Main> parse p_text "(unknown)" "{\"test\":3}" Right (JObject (JObj {fromJObj = [("test",JNumber 3.0)]}))
ちゃんと動いた。JSONの例題は5,6,16章ととびとびになっているので全体像が掴みにくかった。