読者です 読者をやめる 読者になる 読者になる

ParsecでApplicativeを使ってみる

Haskell

Applicativeを使うとParsecが書きやすくなると聞いたのでやってみました。
"(123)"という文字列から、カッコに囲まれた123という値を取り出す処理です。


Applicativeを使わない場合:

import Text.Parsec
import Text.Parsec.String

parseText :: Parser Int
parseText = do
                value <- between (char '(') (char ')') $ many1 digit
                return (read value)

run :: Show a => Parser a -> String -> IO ()
run p input
        = case (parse p "" input) of
            Left err -> do{ putStr "parse error at "
                          ; print err
                          }
            Right x  -> print x

main = do
        run parseText "(123)"
123


Applicativeを使った場合:

import Text.Parsec
import Text.Parsec.String
import Control.Applicative

parseText :: Parser Int
parseText = read <$> (char '(' *> many1 digit <* char ')')

run :: Show a => Parser a -> String -> IO ()
run p input
        = case (parse p "" input) of
            Left err -> do{ putStr "parse error at "
                          ; print err
                          }
            Right x  -> print x

main = do
        run parseText "(123)"
123

Applicativeを使うと、doとreturnが消えました。
この程度の規模だと、効果があまりわからないですが、若干短くはなりました。
個人的にはdoを使ったほうが読みやすいですし、書きやすいです。


追記:
Applicativeのbetween使った版。*>の書き方を把握するために、前のバージョンは残しておきます。

import Text.Parsec
import Text.Parsec.String
import Control.Applicative

parseText :: Parser Int
parseText = read <$> (between (char '(') (char ')') $ many1 digit)

run :: Show a => Parser a -> String -> IO ()
run p input
        = case (parse p "" input) of
            Left err -> do{ putStr "parse error at "
                          ; print err
                          }
            Right x  -> print x

main = do
        run parseText "(123)"
123