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

成らぬは人の為さぬなりけり

エンジニアライフをエンジョイする為のブログ

すごいHaskellたのしく学んでみる-その7

久々のHaskellです。


前回からの続きは「すごいH本」的にはIOの章なんですが、
この辺よりも、その次の章が面白かったので、
ブログに書くのはやめました。


と、いうわけで、今回のテーマは、、、

関数型問題解決法

関数型でなんかプログラム書いてみようぜ、的なノリ・・・?

逆ポーランド記法電卓

これは、初めて知りました。(常識なんでしょうか?)
RPN(reverse polish notation)と呼ばれるそうです。
具体的にどういう記法かというと。。。

通常の式

(1 + 3) * 10 / 2

RPN

1 3 + 10 * 2 /

こうなります。


簡単に言うと、左から順番に評価していき、

[数字][数字][記号]

という並びが出てきたら、計算する。
みたいな感じのようです。

[数字][数字][数字][記号]

だと

[数字]([数字][数字][記号])

こういう評価になります。


ではこの数式をパースして、計算する電卓を書いてみたいと思います。

rpn :: String -> Int
rpn = head . foldl func [] . words
    where func (x:y:ys) "*" = (y * x) : ys
          func (x:y:ys) "+" = (y + x) : ys
          func (x:y:ys) "-" = (y - x) : ys
          func xs numberStr = read numberStr:xs

うん、なんかこんなにもスッキリ書けてしまうんですね。
すげぇ。

最初見た時、なんでyからx引くんだ???
ってなりましたが、
「read numberStr:xs」
なので、逆順に並ぶからでした、、orz


実行してみます。

*Main> rpn "10 4 3 + 2 * -"
-4

よし、上手くできているようです。


では、これに演算子を足してみようと思います。

rpn :: String -> Int
rpn = head . foldl func [] . words
    where func (x:y:ys) "*" = (y * x) : ys
          func (x:y:ys) "+" = (y + x) : ys
          func (x:y:ys) "-" = (y - x) : ys
          func (x:y:ys) "/" = (y / x) : ys
          func (x:y:ys) "^" = (y ** x) : ys
          func xs numberStr = read numberStr:xs

すごく簡単に演算子を追加できました。


今日はここまでにしようかと思います。
次回はFunctorかな?