2013年12月1日日曜日

[Haskell][Clojure]逆ポーランド記法の解析処理

Learn You a Haskell for Great Good で書かれていた逆ポーランド記法の解析処理をClojureで書いてみた。
四則演算のみサポートする単純な処理である。

Haskellの場合

module RPN where
       
solveRPN :: String -> Double
solveRPN = 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 xs num = read num : xs

*RPN> solveRPN "1 2 + 3 * 1 - 2 /"
4.0
     
whereを使うとコードが分かり易くて、なかなか良いね。

Clojureの場合

(ns rpn.core
  (:use [clojure.string :only (split)]))

(defn words [s]
  (split s #"\s+"))

(defn op2 [[x y & ys] f]
  (conj ys (apply f [y x])))

(defn operate [stack item]
  (case item
    "+" (op2 stack +)
    "-" (op2 stack -)
    "*" (op2 stack *)
    "/" (op2 stack /)
    (conj stack (Double/parseDouble item))))

(defn solve-rpn [exprs]
  (first (reduce operate '() (words exprs))))

rpn.core> (solve-rpn "1 2 + 3 * 1 - 2 /")
4.0

solve-rpn関数の中でoperate関数を定義することも可能だが、かえって分かり難くなりそうなので、外出しして関数定義した。
Haskellに比べると冗長になってしまった。
もっと、すっきり書けるのかな?
文字列のdouble型への変換 (Double/parseDouble item) は美しくない。→と思ったときは parse-double関数を作れば良いのだけど。