更新されない定数リストの落とし穴
この前、マスターマインドのプログラムを書いたときに遭遇したこと。
以下の関数 random-digits は、与えられた引数を長さとする数字の順列をひとつ返す。ただしバグあり。
CL-USER> (defun random-digits (num) ; wrong (do ((digits '(0 1 2 3 4 5 6 7 8 9)) (result nil) (count 0 (1+ count)) (rest 10 (1- rest))) ((>= count num) result) (let ((d (nth (random rest) digits))) (push d result) (setq digits (delete d digits))))) RANDOM-DIGITS CL-USER> (random-digits 4) (5 6 4 8) CL-USER> (random-digits 4) (NIL 9 NIL NIL)
digits が前の呼び出しで書き換えられたままになっている。使う数字のリストを毎回生成すれば解決する。
CL-USER> (defun random-digits (num) ; correct (do ((digits (list 0 1 2 3 4 5 6 7 8 9)) (result nil) (count 0 (1+ count)) (rest 10 (1- rest))) ((>= count num) result) (let ((d (nth (random rest) digits))) (push d result) (setq digits (delete d digits))))) RANDOM-DIGITS CL-USER> (random-digits 4) (0 7 8 3) CL-USER> (random-digits 4) (2 5 9 4) CL-USER> (random-digits 4) (0 4 8 6)