Shammer's Philosophy

My private adversaria

Lisp Condition Level 2

概要

以前、Lisp Condition Level 1 - Shammerismで、Runtime で定義済の何らかの処理で例外が発生した場合に、それをどのように捕捉するかということをやってみたことがある。かなり前のことだが、今度は自作の condition を投げるということをやってみる。Clozure CL では文字列を連結させるのに (concatenate 'string first-string other-string1 other-string2 ...) というように書くが、長いので concat とできるようにする。たしか emacs lisp ではこれが使えたはず。

自作 Condition の作成

condition の定義には、define-condition を使用する。引数に string 以外がある場合にはこれを投げる。Beyond Exception Handling: Conditions and Restartsの例を参考にした。

(define-condition arguments-not-string-error (error)
  ((text :initarg :text :reader get-error-message)))

concat の実装

こんな感じにしてみた。

(defun concat (string1 &rest strings)
  (labels ((string-listp (l)
	     (if (null l)
		 t
		 (if (listp l)
		     (and (stringp (car l)) (string-listp (cdr l)))))))
    (if (stringp string1)
	(cond ((null strings)
	       string1)
	      ((stringp strings)
	       (concatenate 'string string1 strings))
	      ((string-listp strings)
	       (let ((result string1))
		 (dolist (s strings)
		   (setf result (concatenate 'string result s)))
		 result))
	      (t
	       (error
		(make-condition
		 'arguments-not-string-error
		 :text "Passed arguments includes objects which is not a string."))))
	(error
	 (make-condition
	  'arguments-not-string-error
	  :text (format nil "concat first argument should be string, but ~A is ~A."
			string1 (type-of string1)))))))

実行結果

なんかよくわからんエラーが出る。

? (concat "abc" 100)
> Error: The value NIL is not of the expected type REAL.
> While executing: CCL::>-2, in process listener(1).
> Type :POP to abort, :R for a list of available restarts.
> Type :? for other options.
1 >

上記に続いて以下のようにやると投げられているように見えるので、

1 > :R
>   Type (:C <n>) to invoke one of the following restarts:
0. Return to break level 1.
1. #<RESTART ABORT-BREAK #x21920C8D>
2. Use a new value of type REAL instead of NIL.
3. Return to toplevel.
4. #<RESTART ABORT-BREAK #x2192153D>
5. Reset this thread
6. Kill this thread
1 > 2
Invoking restart: Use a new value of type REAL instead of NIL.
New value of type REAL :10
> Error: Error #<ARGUMENTS-NOT-STRING-ERROR #x302000F7AAAD>
> While executing: CONCAT, in process listener(1).
> Type :POP to abort, :R for a list of available restarts.
> Type :? for other options.
1 >

make-condition の処理で何かが nil になって失敗しているように見える。一体、何がいけないのだろうか。make-condition なんて自分は初めてでも多くの人がやっているはずだし実際に自作じゃない condition はエラーにならずに投げられているし。。。