ファイヤープロジェクト
集合とキーワード引数
2003-10-14T06:30+09:00   matsu
Lispの集合を扱う関数を試してみた.これらの関数のいくつかには,キーワード引数という引数がある.
ある集合に要素が存在するかどうかはmemberという関数で調べることができる.
> (setf aset '(a b c d e f g))
(A B C D E F G)
;; asetにdがあるかどうか
> (member 'd aset)
(D E F G)
> (setf bset '(a b (c d) e f g))
(A B (C D) E F G)
;; bsetに(caddr bset)があるかどうか(式の意味的にあるに決まっているが...)
> (member (caddr bset) bset)
((C D) E F G)
;; bsetに'(c d)があるかどうか
> (member '(c d) bset)
NIL
このように,memberは第一引数で指定したオブジェクトと同じオブジェクトがあれば,それをcar部にもつコンスを返す.デフォルトでは同じオブジェクトかどうかは,eqlで判断される.これは上の例の三つ目のmember式の返り値がnilであることからも想像がつく.これをequalで判断させるには,member関数にキーワード引数と呼ばれるものを指定する.
> (member '(c d) bset :test #'equal)
((C D) E F G)
memberに似た関数member-ifは引数で指定されたリストから,引数で指定された述語を満たす要素をcar部にもつコンスを返す.
> (member-if #'consp '(a b (c d) e))
((C D) E)
※集合の要素に指定したものがあるかどうかは返り値がnilかどうかで分かる.
Lispの関数には,キーワード引数をとるものがある.
  • キーワード引数の指定は任意
  • キーワード引数を複数とることができる関数もある
  • 複数のキーワード引数の順序は自由
  • キーワード引数はコロン":"とキーワードによるシンボルとともに指定する(これによりキーワード引数の順序を自由に指定することができる).
    (function 引数... :キーワード1 値 :キーワード3 値 :キーワード2 値...)
    
集合の和差積はunion,set-difference,intersectionで得ることができる.
;; 集合の和
> (union '(a b c) '(b c d))
(A B C D)
;; 集合の差((a b c) - (b c d))
> (set-difference '(a b c) '(b c d))
(A)
;; 集合の積
> (intersection '(a b c) '(b c d))
(B C)
集合なので,返り値のリストの要素の順序は補償されない.
先述のunionは集合を対象にした関数である.では,引数に集合ではないもの,すなわち同じ要素が複数あるリストを引数にするとどうなるだろうか.
> (union '(a a b c) '(d e))
(A A B C D E)
> (union '(a a b c) '(a d e))
(B C A D E)
なんだかよくわからない.とにかく集合を対象にした関数であるならば,集合を渡すのが筋というものだろう.ということで,集合を生成したい.集合を生成するには,adjoinという関数を使用する.adjoinは第一引数が第二引数の要素になければconsする.
;; (a b c)にはすでにaがあるのでconsしない
> (adjoin 'a '(a b c))
(A B C)
;; (a b c)にはまだdがないのでconsする
> (adjoin 'd '(a b c))
(D A B C)
adjoinはmemberと同様,すでに要素があるかどうかの判定はデフォルトではeqlで,それはキーワード引数testで変更できる.
> (adjoin '(a b) '((a b) c d))
((A B) (A B) C D)
> (adjoin '(a b) '((a b) c d) :test #'equal)
((A B) C D)
memberやadjoinにはキーワード引数としてkeyがある.testはデフォルトではその値で指定された関数を各要素全体に適用した.keyを使用すると各要素全体ではなく,keyで指定した関数を各要素に適用してその返り値に対してtestで指定した関数を適用するようになる.すなわち
  • 各要素にkeyで指定した関数を適用.
  • その返り値にtestで指定した関数を適用.
  • その返り値がmemberやadjoinの結果に反映される.
なんだかわかりにくいが,例を示すとわかりやすいだろうか.
;; そのcar部がcである要素を確認
> (member 'c '((a b) (c d) (e f)) :key #'car)
((C D) (E F))
;; そのcar部がdである要素を確認
> (member 'd '((a b) (c d) (e f)) :key #'car)
NIL
;; そのcdr部のcar部がdである要素を確認
> (member 'd '((a b) (c d) (e f)) :key #'cadr)
((C D) (E F))
matsu(C)
Since 2002
Mail to matsu