Haskell: ミニコンパイラの解体
前のエントリで、Haskellで実装したミニコンパイラを紹介しました。今回はこのミニコンパイラの字句解析のパーツだけを取り出して動かしてみます。必要最小限なコードを切り出して動作させてみたかったので、今回対応する計算式は「自然数の足し算」のみです。ミニコンパイラから、そのような興味のあるコードだけを抜き出してみると、以下のようになりました。
% vim calc.hs import Char data Token = NUM Int | PLUS instance Show Token where showsPrec p (NUM num) = showString "NUM " . shows num showsPrec p (PLUS) = showString "PLUS" tokenise :: [Char] -> [Token] tokenise [] = [] tokenise ('+':rest) = PLUS : (tokenise rest) tokenise (ch:rest) | isDigit ch = let (n, rest2) = convert(ch:rest) in (NUM n):(tokenise rest2) convert :: [Char] -> (Int, [Char]) convert str = let conv' [] n = (n, []) conv' (ch : str) n | isDigit ch = conv' str ((n*10) + digitToInt ch) | otherwise = (n, ch : str) in conv' str 0 main :: IO () main = do expr <- getLine putStrLn(show(tokenise expr))
ghcでコンパイルして実行すると、以下のようになります。期待通りに字句解析できていますね。
% ghc -o calc calc.hs % ./calc 1+2+3 [NUM 1,PLUS,NUM 2,PLUS,NUM 3]
Haskellの理解度はまだまだ低いですが、解体作業をしていて、以下がポイントだと思いました。
- import Char: isDigit関数とdigitToInt関数を利用するために必要
- data Token ... : トークンを表現するためにTokenというデータ構造を定義
- instance Show Token ... : Token型を文字列に変換できるように(JavaのtoString()的な考え方)
- tokenise関数
また、今回解体作業をしていて、動作保証されたお手本のコードから興味のあるコードを取り出して、それを動作するまで試行錯誤するというアプローチは、とても勉強になると思いました。Haskellを使いこなせるようになるまでの道のりは険しいと思いますが、少しずつ頑張ればなんとかなるような気がします。