前回 Text.Parsec の記事を書いてから、ひと月以上あいてしまった。なんか途中で書くモチベーションが下がったりもしたんだけど、今日は時間がとれたので書く。前回良くわからなかった、パーサの型についてだ。
ここ↓が参考になった。
cf. Parsec3 におけるパーサーの型 – k16’s note
このページによると、
- パーサの厳密な型シグネチャは
ParsecT s u m a
- s は抽象化された入力の型。この抽象化された入力をストリームという
- u はパース時に好きな状態を格納しておく容器の型
- m はモナド変換子にとって基盤となるモナド
- a は出力の型
モナド変換子というのは、ここでは ParsecT
のことで、正直なんだかよくわからない。
前回書いたコードにある wave
パーサの場合、入力は文字列(String
)、出力は少数点数のリスト([Double]
)で、m
がモナドである必要があるから、次のようになる。
wave :: Monad m => ParsecT String u m [Double]
コード全体を載せると:
module Main where import System.Environment ( getArgs ) import Text.Parsec -------------------------------------------------------------------------------- main :: IO () main = do args <- getArgs cs <- readFile (head args) let wv = parseWave cs either (\ e -> print e) (\ w -> putStr $ unlines $ map show w) wv -------------------------------------------------------------------------------- -- Parsers wave :: Monad m => ParsecT String u m [Double] wave = do ls <- many1 waveLine eof return $ concat ls waveLine :: Monad m => ParsecT String u m [Double] waveLine = do ws <- many1 waveData newline return ws waveData :: Monad m => ParsecT String u m Double waveData = do d <- count 8 dataChar return $ read d dataChar :: Monad m => ParsecT String u m Char dataChar = digit <|> oneOf "-. " -------------------------------------------------------------------------------- parseWave :: String -> Either ParseError [Double] parseWave input = parse wave "(unknown)" input --------------------------------------------------------------------------------
実行例:
takatoh@apostrophe $ runhaskell parsewave0.hs data0.dat > result0.txt takatoh@apostrophe $ head result0.txt -5.0e-2 -5.0e-2 -5.0e-2 -5.0e-2 -6.0e-2 -6.0e-2 -6.0e-2 -6.0e-2 -6.0e-2 -7.0e-2
話はさらに続く。Text.Parsec.String
には、次のような定義がある。
type Parsec s u = ParsecT s u Identity
type Parser = Parsec String ()
上は ParsecT
のモナドに Identity
を使ったもの、下はその Parsec
の入力に String
、容器に ()
を使ったものだ。これを使うと、前述の wave
パーサの型は次のように簡潔に書ける。
wave :: Parser [Double]
コード全体を載せよう。
module Main where import System.Environment ( getArgs ) import Text.Parsec import Text.Parsec.String -------------------------------------------------------------------------------- main :: IO () main = do args <- getArgs cs <- readFile (head args) let wv = parseWave cs either (\ e -> print e) (\ w -> putStr $ unlines $ map show w) wv -------------------------------------------------------------------------------- -- Parsers wave :: Parser [Double] wave = do ls <- many1 waveLine eof return $ concat ls waveLine :: Parser [Double] waveLine = do ws <- many1 waveData newline return ws waveData :: Parser Double waveData = do d <- count 8 dataChar return $ read d dataChar :: Parser Char dataChar = digit <|> oneOf "-. " -------------------------------------------------------------------------------- parseWave :: String -> Either ParseError [Double] parseWave input = parse wave "(unknown)" input --------------------------------------------------------------------------------
実行例:
takatoh@apostrophe $ runhaskell parsewave0a.hs data0.dat > result0a.txt takatoh@apostrophe $ head result0a.txt -5.0e-2 -5.0e-2 -5.0e-2 -5.0e-2 -6.0e-2 -6.0e-2 -6.0e-2 -6.0e-2 -6.0e-2 -7.0e-2
ふぅ、今日はここまで。