逆ポーランド電卓

エラーチェックはありません。0除算もチェックしていません。コマンドライン引数をそのままリストに変換しているので、変な入力を与えると危険です。

; -*- compile-command: "C:/usr/clisp-2.41/clisp.exe a.l" -*-

(defun op (f stack)
  (cons 
   (funcall f (cadr stack) (car stack))
   (cddr stack)))

(defun calc (stack xs_)
  (let ((x (car xs_))
	(xs (cdr xs_)))
    (cond ((null x)
	   (car stack))
	  ((symbolp x)
	   (calc (op x stack) xs))
	  (t
	   (calc (cons x stack) xs)))))

(defun rpcalc (xs)
  (calc '() xs))
 
(defun join(c ss)
  (reduce #'(lambda (a s) (concatenate 'string a c s)) ss))

(defun args-to-list (args)
  (read-from-string (join " " (append '("(") args '(")")))))

(print (rpcalc (args-to-list *args*)))

実行例:

$ clisp.exe a.l "1 2 + 4 * 2 /"

6

疑問点というかひっかかるところ。

  • パターンマッチがないのはキツいです(関数calcのとこ)。
  • 引数で渡した関数を呼び出すのにfuncallが必要なのはちょっと気持ち悪いです。
  • 普通のクォート'と関数のクォート#'の違いがよく分かりません。
  • read-from-stringを使わずに文字列を1つ以上の空白で区切ってリストにする方法がよくわかりませんでした。(気力があったら)その内調べよう。