だいごろうのブログ

熊本出身で大阪、東京、パリを転勤して、今は福岡でデータエンジニアです

ポーランド記法の電卓のパーサをHaskellで書いた

9月といえど、まだまだ外は暑いですね。
子どもたちが公園で遊んでる声で起きました。まだ夏な気がします。

Haskellを初めて触ってみました。

超初心者。関数型言語も。
詳細な書き方の理解は全くなく、
イロイロなものを組み合わせてだんだん動くようになったから
生意気にもブログを書いてる感じです(`・∀・´)エッヘン!!
なので、細かい技術の話は、参考文献の方々のモノを読んでくださいね( ・∀・)ノ

とりあえずソース

daigorowhite/PNDentaku · GitHub

{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative
import Data.Text(pack)
import Data.Char (ord)
import Data.Attoparsec.Text
import Data.Attoparsec.Number
import System.Environment (getArgs)

-- Exp型?の定義
data Exp = Add Exp Exp |
           Sub Exp Exp |
           Mul Exp Exp |
           Div Exp Exp |
           Nat Int deriving Show


-- プログラムの文法 1つ以上の式
prog = many1 expr

-- 式の文法 足し算、引き算、掛け算、割り算、数字のどれか
expr :: Parser Exp
expr =  add <|>
        sub <|>
        mul <|>
        divi <|>
        num

-- 足し算の文法 "(+ EXP EXP)"
add :: Parser Exp
add = Add <$> ("(" *> ("+" *> (spaces *> expr))) <* spaces <*>  expr <* spaces <* ")"
-- (中略)
-- 同じように引き算、掛け算、割り算を書く

-- 数字の文法 "Num"
num :: Parser Exp
num = Nat . read <$> many1 digit

-- 複数のスペースの文法
spaces = many space

-- 引数をパースして出力する
main :: IO ()
main = do
	args <- getArgs;
	print $ parseOnly prog $ pack $ concat args

技術的に

- Attoparsecというものを使ってパーサを書いてる
- 記法を簡単にするために、Applicativeというものを使っている

じゃあ、やってみよう

とりあえずコンパイルする

% ghc dentaku.hs 
[1 of 1] Compiling Main             ( dentaku.hs, dentaku.o )
Linking dentaku ...

実行ファイル( dentaku )ができるので
これを使ってパースしてみる

% ./dentaku "(+ 1 1)"
Right [Add (Nat 1) (Nat 1)]

できたー。
Addが自然数1を2つ持ってる。
後は、ロジックを実装すれば、立派な計算機として動きます。
時間あれば、+の部分を関数名にして、
ロジックで足し算とか分けていけたら、Lisp系の言語ができそう。

haskellの感想

- そもそもhaskellの文法を理解しないとだめだなー
- letとか、関数渡しとか、オブジェクト脳には、何がなんやら。
- 全体的に、なんか、動いた。。。ってことが多い(初心者すぐる)
- とはいえ、よく知ってる言語よりも動いたらうれしー。(よその猫が膝に乗ってきた感じ
次はちゃんと、haskellの書き方を理解しよう(゚д゚)!

インスピレーション受けたやつ

様々な、人とブログと勉強会から刺激を受けています。

スペシャルサンクス

- 発表をしていた@fujiyan18さん
https://gist.github.com/fujiyan/e1b58d3d447843509477
- その勉強会を企画した@kazuhito_mには特に感謝っす。
- プログラム中に僕を支えたハンモック
- 居心地がよく集中力を来れた。グランフロントのCafe.Lab.