ここのところ、( keyword . plist )という感じのリストをよく使っています。
例えば、(:material :specular '(1 0 0 1))みたいな感じです。
手で入力するのはこの程度にとどめたいのですが、デフォルト値とかが他に色々あるので、これを関数に渡して
(:MATERIAL :SPECULAR (0.2 0.2 0.2 1) :DIFFUSE (0.8 0.8 0.8 1) :AMBIENT
(0 0 0 1) :SHININESS 0 :COLOR-MATERIAL NIL)
と、こんな感じのものが取り出せるようにしています。
で、それが以下の関数なんですが、
(defun material (&KEY (specular '(0.2 0.2 0.2 1)) (diffuse '(0.8 0.8 0.8 1)) (AMBIENT '(0 0 0 1)) (SHININESS 0) (COLOR-MATERIAL nil)) (list :material :specular specular :diffuse diffuse :ambient ambient :shininess shininess :color-material color-material))
こんなのをいくつも書くのは結構苦痛だったので、以下のようなマクロを書いて
(defmacro def-primitive-func (name lst) (let ((head (car lst)) (arg (loop for i from 0 below (length (cdr lst)) when (= 1 (mod i 2)) collect (elt (cdr lst) i))) (body (mapcar #'(lambda (x) (if (consp x) (car x) x)) (cdr lst)))) `(defun ,name (&key ,@arg) (list ,head ,@body))))
以下のように使うことにしました。
(def-primitive-func material (:material :specular (specular '(0.2 0.2 0.2 1)) :diffuse (diffuse '(0.8 0.8 0.8 1)) :ambient (ambient '(0 0 0 1)) :shininess (shininess 0) :color-material (color-material nil)))
でも本当は以下のように書きたい。
(def-primitive-func material (:material (specular '(0.2 0.2 0.2 1)) (diffuse '(0.8 0.8 0.8 1)) (ambient '(0 0 0 1)) (shininess 0) (color-material nil)))
文字列を経由すればできそうな気はするんだけど、
文字列を経由しない方法を探してみようかと。
なんだかツイートの延長っぽいかんじ。