2010年9月8日水曜日

古い値を利用する更新処理(Common Lisp)

Clojureのswap!はアトムの古い値を引数にして関数を呼び出し、その結果を新しい値とします。たしか。

似たような値の更新方法をCommon Lispで計4パターン書いてみました。

(defmacro update/fn-1! (generaized-variable update-fn &rest args)
(let ((old-val (gensym)))
`(let ((,old-val ,generaized-variable))
(setf ,generaized-variable (funcall ,update-fn ,old-val ,@args))
,old-val)))

(defmacro update/fn-2! (generaized-variable update-fn &rest args)
`(setf ,generaized-variable
(funcall ,update-fn ,generaized-variable ,@args)))

(defmacro update/fn-r-1! (generaized-variable update-fn &rest args)
(let ((old-val (gensym)))
`(let ((,old-val ,generaized-variable))
(setf ,generaized-variable (funcall ,update-fn ,@args ,old-val))
,old-val)))

(defmacro update/fn-r-2! (generaized-variable update-fn &rest args)
`(setf ,generaized-variable
(funcall ,update-fn ,@args ,generaized-variable )))

;;example
(let ((a 0)) (update/fn-1! a #'cons 1) a)
=>(0 . 1) ; (cons 古い値 引数)
(let ((a 0)) (update/fn-r-1! a #'cons 1) a)
=>(1 . 0) ; (cons 引数 古い値)

(let ((a 0)) (update/fn-1! a #'cons 1))
=>0 ; 古い値が返る
(let ((a 0)) (update/fn-2! a #'cons 1))
=>(0 . 1) ; 新しい値が返る

fnとfn-rの違いは、古い値が関数の引数として渡される際、第1引数となるか最後の引数となるかです。

1と2の違いは、返り値として古い値を返すか新しい値を返すかです。

どのパターンが有用なのかは、使ってみないことには判断できないような気がします。

0 件のコメント:

コメントを投稿