うじひささん主催のHaskell勉強会#9に行ってきました。
今回はふつケルのp.318からp.332まで読み進めました。Parsec(sayではぱーせく)のあたりです。
最後にやった演習で結局宿題になった”逆ポーランド記法のパーサを書こう”を頑張ってやってみました。
(02/25:追記)
うじひささんの指摘を受けて先頭のスペースを無視する様に修正しました。
import Text.ParserCombinators.Parsec data RPNExpr = Error | Expr Int Int Char main = do expr <- getContents mapM_ (print . calc . compileRPN) (lines expr) calc :: RPNExpr -> Int calc Error = -99 calc (Expr x y '+') = x + y calc (Expr x y '-') = x - y calc (Expr x y '*') = x * y calc (Expr x y '/') = case y of 0 -> 0 y -> x `div` y compileRPN :: String -> RPNExpr compileRPN cs = case parse rpn "" cs of Right expr -> expr Left err -> Error rpn :: Parser RPNExpr rpn = do many space n1 <- try sector <|> digit' n2 <- try sector <|> digit' opt <- operator return $ Expr n1 n2 opt where sector :: Parser Int sector = do char '(' expr <- rpn char ')' many space return $ calc expr digit' :: Parser Int digit' = do n <- many1 digit many1 space return $ read n operator :: Parser Char operator = do opt <- oneOf "+-*/" many space return opt
main関数はうじひささんのもののパクリ。
左結合での再帰は無限ループになって書けないみたいなのでずるいですが、式を()でくくるように強制しています。
全体的に手抜きなので、パースに失敗した場合は-99を返す仕様。-99に意味はありません。
結果
4 5 + 9 (2 3 +) 2 * 10 (1 3 +) (8 3 -) * 20
とりあえず結果は出てるのでよしとしましょう。
うじひささんの”もうちょっとまともなver.”に期待しつつも僕もいづれちゃんと書き直そうとちいさな決心。