ファイヤープロジェクト
ストラクチャ
2003-11-03T18:00+09:00   matsu
ストラクチャはいわゆる構造体だが,Lispのそれはなんかすごい.
ストラクチャはdefstructで作成できる.フィールドname,ageをもつ構造体personは以下のようにして作成できる.
> (defstruct person
name
age) 
PERSON
LispプログラムはLispプログラムを作成できるが,defstructは良い例だろうか.この例ではdefstructを呼び出した時点で,以下の関数が同時に作成される.
make-person
関数名が「make-構造体名」の形式の関数.該当する構造体を生成する.
person-p
関数名が「構造体名-p」の形式の関数.引数が該当する構造体かどうかを判定する.
copy-person
関数名が「copy-構造体名」の形式の関数.引数を該当する構造体とし,そのコピーを返す.
person-name
関数名が「構造体名-フィールド名」の形式の関数.引数を該当する構造体とし,該当するフィールドの値を返す.
person-age :構造体名-フィールド名
同上.
試してみる.
> (defstruct person
name
age) 
PERSON
;; personという構造体を作成し,name="HOGE",age=10で初期化.
> (setf hoge (make-person :name "HOGE" :age 10))
#S(PERSON :NAME "HOGE" :AGE 10)
> (person-p hoge)
T
> (person-name hoge)
"HOGE"
> (person-age hoge)
10
> (setf fuga (copy-person hoge))
#S(PERSON :NAME "HOGE" :AGE 10)
;; 例によって構造体のフィールドの値はsetfで設定できる.
> (setf (person-name fuga) "FUGA")
"FUGA"
> hoge
#S(PERSON :NAME "HOGE" :AGE 10)
> fuga 
#S(PERSON :NAME "FUGA" :AGE 10)
「make-構造体名」で構造体の実体を生成できるが,その時にフィールド名の初期化値を指定できた.
> (defstruct person
name
age) 
PERSON
;; personという構造体を作成し,name="HOGE",age=10で初期化.
> (setf hoge (make-person :name "HOGE" :age 10))
#S(PERSON :NAME "HOGE" :AGE 10)
「make-構造体名」を呼び出すときに初期化値を指定しなければ以下のようになる.
> (defstruct person
name
age) 
PERSON
> (make-person)
#S(PERSON :NAME NIL :AGE NIL)
ここではNILだが,それは処理系による.あとで初期化した方がよい.だが,うれしいことにdefstructの際にデフォルトの初期化値を指定することができる.
> (defstruct person (age 0) (name "who"))      
PERSON
> (make-person)
#S(PERSON :AGE 0 :NAME "who")
> (make-person :age 100 :name "HOGE")
#S(PERSON :AGE 100 :NAME "HOGE")
> (make-person :name "HOGE")
#S(PERSON :AGE 0 :NAME "HOGE")
> (make-person :age 100)
#S(PERSON :AGE 100 :NAME "who")
もちろん「make-構造体名」を実行時に値を指定すればそれで初期化される.注意点としては,初期化値にlispが処理できない指定を行なってもdefstruct時には怒られず,「make-構造体名」によってその初期化値で埋められるときに怒られることである.
> (defstruct person (age 0) (name who))
PERSON
[14]> (make-person )

*** - EVAL: variable WHO has no value
> (make-person :name "HOGE")
#S(PERSON :AGE 0 :NAME "HOGE")
この例でいうとdefstruct時には(name who)は評価されず,「make-構造体名」でデフォルトの初期化値を埋める時に評価されると想像できる.すなわち他の関数と同様,(name who)の部分は任意の式にできる.
> (make-person :name "HOGE")
#S(PERSON :AGE 0 :NAME "HOGE")
> (defstruct person
(age (progn (format t "age?") (read)))
(name (progn (format t "name?") (read))))
PERSON
> (make-person )
age?100
name?hoge
#S(PERSON :AGE 100 :NAME HOGE)
この例は初期化値を指定せずにmake-personを呼び出すとreadでユーザに問い合わせている.
defstructすると同時にいろんな関数が作成される.そのうちの一つに「構造体名-p」があった.つまり関数に加えて型も作成される.すなわち
> (defstruct person
name
age) 
PERSON
> (setf hoge (make-person :name "HOGE" :age 10))
#S(PERSON :NAME "HOGE" :AGE 10)
> (person-p hoge)
T
> (typep hoge 'person)
T
typepは汎用的な型チェック関数である.第一引数が第二引数のシンボルで表される型かどうかを判定する.すなわち上の例の最後の式はpersonという型があってhogeはその型の変数であることを示している.ちなみにclisp処理系ではtypepに存在しない型を指定すると以下のようになった.
> (typep hoge 'persoon)

*** - TYPEP: invalid type specification PERSOON
ちなみにstructure型はatomでありtである.
> (defstruct person
name
age) 
PERSON
> (setf hoge (make-person :name "HOGE" :age 10))
#S(PERSON :NAME "HOGE" :AGE 10)
> (typep hoge 'atom)
T
> (typep hoge 't)
T
matsu(C)
Since 2002
Mail to matsu