[Haskell] Parsec (Haskellのパーサーライブラリー)

ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門 読み終わりました ^^)

さすがに最後のパーサーの部分は難易度が高かったです。 型、クラス、モナドなどの理解が良く出来てないのが露呈し、またその部分を読みながらサンプルコードをなんとか読みきりました。

そこで、Parsecを使って、以下のBNFで表されるような 指数部付き整数 (? なんだそれですが・・・)

<num> ::= <int> | <e_int>
<int> ::= <uint> | - <uint>
<uint> ::= <digit> | <uint> <digit>
<digit> ::= 0 | 1 | ... | 9
<e_int> :: = <int> E <uint>

のパーサーを Parsec を使って書いてみました。

import Text.ParserCombinators.Parsec

num :: Parser Int
num = do n <- try(e_int)
         return  n
 <|>  do n <- int
         return  n

e_int :: Parser Int
e_int = do n <- int
           s <- char 'E'
           e <- uint
           return $ n * pow10(read e)  

int :: Parser Int
int = do char '-'
         n <- uint
         return  $ - read n
 <|>  do n <- uint
         return $ read n

uint :: Parser String
uint = do d <- many1 (digit)
          return d

pow10 :: Int -> Int
pow10 n = if n == 0 then 1 else 10 * pow10(n - 1)
   

evalNum :: String -> Int
evalNum s = case parse num "" s of
              Right n -> n
              Left err -> -1

苦節、数時間 やっとできました ^^)!

こんな感じで動きます (gchi上で)

*Main> evalNum "1234"
1234
*Main> evalNum "-1234"
-1234
*Main> evalNum "-1234E3"
-1234000