Lispクロージャの典型的な例は、カウンターを返す次の関数です。
(defun make-up-counter ()
(let ((n 0))
#'(lambda () (incf n))))
呼び出されると、カウントがインクリメントされ、結果が返されます。
CL-USER > (setq up1 (make-up-counter))
#<Closure 1 subfunction of MAKE-UP-COUNTER 20099D9A>
CL-USER > (funcall up1)
1
CL-USER > (funcall up1)
2
Lispに慣れていない友人にこれを見せたとき、彼はカウンターをコピーして同じタイプの新しい独立したカウンターを作成する方法を私に尋ねました。これは機能しません:
CL-USER > (setq up2 up1)
#<Closure 1 subfunction of MAKE-UP-COUNTER 20099D9A>
up2は新しいカウンターではないため、同じカウンターの名前が異なるだけです。
CL-USER > (funcall up2)
3
これが私の最善の試みです:
(defun make-up-counter ()
(let ((n 0))
#'(lambda (&optional copy)
(if (null copy)
(incf n)
(let ((n 0))
#'(lambda () (incf n)))))))
カウンターのコピーを返すには、引数tを指定して呼び出します。
(defun copy-counter (counter) (funcall counter t))
これは、第1世代のコピーで機能します。
CL-USER > (setq up2 (copy-counter up1))
#<Closure 1 subfunction of MAKE-UP-COUNTER 200DB722>
CL-USER > (funcall up2)
1
しかし、up2をコピーしようとすると、明らかに機能しません。メイクアップカウンターの定義には、それ自体の定義内にそれ自体のコピーが必要であるため、正しく機能させる方法がわかりません。
助言がありますか?
これを解決するには、次を使用して再帰関数を使用する必要がありますlabels
。
(defun make-up-counter ()
(labels ((new ()
(let ((n 0))
(lambda (&optional copy)
(if copy
(new)
(incf n))))))
(new)))
copy
trueの場合、現在のカウンター値をコピーするようにすることもできます。
(defun make-up-counter ()
(labels ((new (n)
(lambda (&optional copy)
(if copy
(new n)
(incf n)))))
(new 0)))
両方のcopy
長所を生かすために、が数値の場合は指定された値でカウンターを作成することができます。それ以外の場合は、正しければカウンター値をコピーし、そうでない場合はインクリメントします。
(defun make-up-counter ()
(labels ((new (n)
(lambda (&optional copy)
(cond ((numberp copy) (new copy))
(copy (new n))
(t (incf n))))))
(new 0)))
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加