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 件のコメント:
コメントを投稿