List的なものをパースしたい

まぁ全く必要に迫られている訳では無いのですが、日々JavaでかつAndroidアプリ開発をしていると、精神衛生上いろいろとあるので、少し触って放置していたParsecで遊んでみることに。

前回四則計算をやったような気がするので、今回もこじんまりとリストのパースを試してみました。思いっきり我流なのでまぁあれかとは思うけれども、一応メモ的な感じで。

import Text.ParserCombinators.Parsec

data Item = List [Item] | Prim Prim deriving Show
data Prim = String String | Num Int deriving Show

main = do cs <- getContents
          case parse list "" cs of
               Right result -> putStrLn $ "Result:" ++ show result
               Left err -> putStrLn $ "Error:" ++ show err

list :: Parser Item
list = do char '['
          x <- item
          xs <- many item2
          char ']'
          return $ List $ x:xs

item :: Parser Item
item = prim <|> list

item2 :: Parser Item
item2 = char ',' >> item >>= \x -> return x

prim :: Parser Item
prim = do x <- str <|> num
          return $ Prim x

str :: Parser Prim
str = do char '\"'
         s <- many $ noneOf "\""
         char '\"'
         return $ String s

num :: Parser Prim
num = many1 digit >>= \s -> return $ Num (read s::Int)

で、これを実行させてみると

komamitsu@carrot:~/lab/haskell$ runghc ListParser.hs
[123,["abc",4,[[5,6,"def"],["g","h"],7,8],"ijk"],"lm",9]

こんな結果がでて良かったですねぇという。

Result:List [Prim (Num 123),List [Prim (String "abc"),Prim (Num 4),List [
List [Prim (Num 5),Prim (Num 6),Prim (String "def")],List [Prim (String "g"),Prim (String "h")],
Prim (Num 7),Prim (Num 8)],Prim (String "ijk")],Prim (String "lm"),Prim (Num 9)]

まぁParsecがモナド的にどうなっているのかは全然わかってないのですが、すごい綺麗に書けてすごい嬉しいですねぇ。