Shammer's Philosophy

My private adversaria

dolist 排除計画その2

概要

dolist 排除計画その1 - Shammerismで、自作関数の concat から dolist を排除しようと再帰を取り入れたものの、初期実装は失敗。入れ子のリストをフラットにする処理例がHow to remove nested parentheses in LISP - Stack Overflowにあったので、その処理を引用。

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))))))
	   (conc (l)
	     (if (null l)
		 ""
		 (concatenate 'string (car l) (conc (cdr l)))))
	   (flatten (l)
	     (cond ((null l) nil)
		   ((atom (car l)) (cons (car l) (flatten (cdr l))))
		   (t (append (flatten (car l)) (flatten (cdr l)))))))
    (if (stringp string1)
	(cond ((null strings) string1)
	      ((string-listp strings) (conc (flatten (list string1 strings))))
	      (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 "a" "b" "c")
"abc"
? (concat "abc" "def" "ghi" "jkl" "mno" "pqr" "stu" "vxxyz")
"abcdefghijklmnopqrstuvxxyz"
?

今度こそ完成???やっぱり再帰を使った方がコード自体はスッキリする気がする。もちろん、ロジック的に再帰より繰り返しの方が適切な場合もあるだろうから、どちらを使うかはケースバイケースだ。