Shammer's Philosophy

My private adversaria

Lisp selective box ver 20151124?

どのように呼べばいいかわからないのでこういうタイトルにしてみた。何らかの入力を伴うプログラムで、無効な値が入力された際には有効な値が入力されるまで繰り返し入力を促したい、という場合がある。全て網羅するのは大変なので、手始めに項番と項目のペアで有効な項番を選択させる、というものを書いてみた。

(defun select-valid-cons (lst message)
  (when (typep lst 'list)
    (let (valid-values key-type)
      (format t "~A~%" message)
      (dolist (i lst)
	(cond ((typep i 'cons)
	       (format t "~A. ~A~%" (first i) (second i))
	       (cond ((null key-type)
		      (cond ((typep (first i) 'integer)
			     (setf key-type 'integer)
			     (push (first i) valid-values))
			    (t
			     (setf key-type (first (type-of (first i))))
			     (push (first i) valid-values))))
		     (t
		      (if (equal key-type (first (type-of (first i))))
			  (push (first i) valid-values)
			  (format t "The key type of ~A is not equal others, ignore this element.~%" (first i))))))
	      (t
	       (format t "The type of ~A is not CONS, ignore this element.~%" i))))
      (do () ()
	(let ((value (if (equal key-type 'integer)
			 (read)
			 (read-line))))
	  (if (member value valid-values :test #'equal)
	      (return (first (member value lst :key #'car)))
	      (format t "Your value ~A is not valid. Please select the correct one.~%" value)))))))

Both 0 and 1 are not integer on Lisp? - Shammerismの例があるので、項番に数字を使用した場合はtype-ofでなくintegerを明示的に指定するようにした。(type-of 0)と(type-of 1)はBITになってしまうが、(typep 0 'integer)も(typep 1 'integer)もTになる。

これは以下のように使用できる。

? (select-valid-cons '((1 "Apple") (2 "Banana") (3 "Orange")) "What is the most favorite fruits?")
What is the most favorite fruits?
1. Apple
2. Banana
3. Orange
daf
Your value DAF is not valid. Please select the correct one.
0
Your value 0 is not valid. Please select the correct one.
1
(1 "Apple")
?