高階関数

置換

リストから要素を一つずつ取り出し(car)、何らかの加工(写像を取る・map)を行い、結果的に入力のリストと対応した同じ長さのリストを得られることから、よく似た foreach 関数とは異なり mapcar 関数の本質は置換にあると言えます。

mapcar 関数に渡す関数は、リストの要素を引数にとり、目的にあったなんらかの値を返すものです。返す値は、nil でもアトムでもリストでも可能です。もっとも簡単なものは以下のようなものです。

(defun function (item)
    (item を元に何らかの値を返す)
)

関数の引数は、ひとつとは限りません。複数の引数を受け付ける関数を指定することも可能で、その場合は対応する引数のリストを複数用意してやる必要がありあます。

(defun function (item1 item2 ...)
    (item1 item2 ... を元に何らかの値を返す)
)

AutoLISP関数
(mapcar 'function list1... listn)
function:関数
list1... listn:リスト
指定されたリストの各要素を引数として関数を実行した結果のリストを返します。
戻り値:リスト

mapcar 関数は、list から要素を順に一つずつと取り出し、それを引数としてfunction を実行し、それぞれの結果を新しいリストに格納します。

下の例ではsqrt 関数にリストの各要素を渡し、各要素の平方根のリストを得ています。

_$ (mapcar 'sqrt '(1 2 3 4 5 6 7)) ⏎
(1.0 1.41421 1.73205 2.0 2.23607 2.44949 2.64575)

function 関数の引数が二つ以上の場合は、対応した複数のリストを並列して引数として追加で渡します。

下の例ではピタゴラスの定理から、二つのリストの同じインデックスの要素を直角三角形の二つの辺として、それぞれの斜辺の長さを納めたリストを得ています。

_$ (mapcar '(lambda (a b) (sqrt (+ (expt a 2) (expt b 2)))) '(3 5) '(4 12)) ⏎
(5.0 13.0)

上の例では、引数が3 と4 の組み合わせ、5 と12 の組み合わせで関数が実行されます。そのため、訳があって引数のリストの長さが異なってしまった場合は、短いリストに合わせて実行されます。

削除

以下のリストの削除関数は、どの要素を削除するのかを決定する判定関数を引数で指定する必要があります。判定関数は、次のように一つの引数を受け取り、nil か nil 以外を返す関数にします。

(defun predicate-function (item)
    (item を検査してnil かnil 以外を返す)
)

どういうケースで nil とするかはプログラミング次第です。

AutoLISP関数
(vl-remove-if ‘predicate-function list)
predicate-function:テスト関数
list:リスト
指定されたリストから、テスト関数が nil 以外を返したものを取り除きます。(指定されたリストから、テスト関数が nil を返した要素を返します。)
戻り値:リスト

vl-remove-if 関数は、リストのフィルタリング関数で、predicate-function 関数が nil を返す要素のみのリストを返します。vl-remove 関数はvl-remove-if 関数の特殊な形式と言えます。

list 引数は検査するリストを指定します。

戻り値のリストは、引数で渡したリストのコピーで、返すリストが無いときは nil を返します。

下は 3 で割り切れる要素を除いたリストを返します。

_$ (vl-remove-if '(lambda (num) (zerop (rem num 3))) '(1 2 3 4 5 6)) ⏎
(1 2 4 5)

関数名が分かりにくいですが、predicate-function 関数が真を返す要素が削除(remove)されるという意味になります。

AutoLISP関数
(vl-remove-if-not 'predicate-function list)
predicate-function:テスト関数
list:リスト
指定されたリストから、テスト関数が nil を返したものを取り除きます。(指定されたリストから、テスト関数が nil 以外を返した要素を返します。)
戻り値:リスト

vl-remove-if-not 関数は、リストのフィルタリング関数で、vl-remove-if 関数とは反対に predicate-function 関数が nil 以外を返す要素のみのリストを返します。

list 引数は検査するリストを指定します。

戻り値のリストは、引数で渡したリストのコピーで、返すリストが無いときは nil を返します。

下は 3 で割り切れない要素を除いたリストを返します。

_$ (vl-remove-if-not '(lambda (num) (zerop (rem num 3))) '(1 2 3 4 5 6)) ⏎
(3 6)

関数名が二重否定になっており、さらに分かりにくいものになっています。predicatefunction 関数が偽を返す要素が削除(remove)されるという意味になります。そこで、例えば「filter」という別の関数名を定義してしまっても良いでしょう。別名の定義は、以下のように行います。

(setq filter vl-remove-if-not)

このように再定義を行うと、先ほどの例が少しは分かりやすくなります。

_$ (filter '(lambda (num) (zerop (rem num 3))) '(1 2 3 4 5 6)) ⏎
(3 6)

評価

以下のリストの評価関数は、どの要素の評価方法を決定する判定関数を引数で指定する必要があります。判定関数は、次のように複数の引数を受け取ることができ、戻り値として nil か nil 以外を返す関数にします。

(defun predicate-function (item1 item2 …)
    (item1 item2 ... を評価して nil か nil 以外を返す)
)

どういうケースで nil とするかはプログラミング次第です。

AutoLISP関数
(vl-every 'predicate-function list [list]...)
predicate-function:テスト関数
list:リスト
「すべて」のリスト要素に対して、テスト関数がnil 以外を返すか調べます。
戻り値:nil、または nil 以外

vl-every 関数は、list から要素を順に取り出し、それを引数として predicate-function で指定した関数を実行します。すべての要素に対して関数が nil 以外を返した時に vl-every 関数は nil 以外を返し、一つでも nil が見つかれば vl-every 関数は nil を返します。

下は、リストの要素がすべて数値かどうかを検査しています。

_$ (vl-every 'numberp (list 1 -2.0 PI (sqrt 16))) ⏎
T

次の例は、判定関数が複数の引数をとる例です。最初の整数のリスト要素が、2 番目のリスト要素よりすべての場合で小さいか判定します。

_$ (vl-every '< '(1 2 3) '(2 4 6)) ⏎
T

ここでは、1 と 2 の組み合わせ、2 と 4 の組み合わせ、3 と 6 の組み合わせで評価が行われます。

AutoLISP関数
(vl-some 'predicate-functionlist [list]...)
predicate-function:テスト関数
list:リスト
「いずれか」のリスト要素に対して、テスト関数が nil 以外を返すか調べます。
戻り値:nil、または nil 以外

vl-some 関数は、list から要素を順に取り出し、それを引数として predicate-function で指定した関数を実行します。一つでも要素に対して関数が nil 以外を返した時に vl-some 関数は nil 以外を返し、すべてが nil であればvl-some 関数は nil を返します。

下は、リストの要素に数値が含まれているかどうかを検査しています。

_$ (vl-some 'numberp (list "1" "-2.0" PI (sqrt 16))) ⏎
T

次の例は、判定関数が複数の引数をとる例です。最初の整数のリスト要素が、2 番目のリスト要素より小さい組み合わせがあるか判定します。

_$ (vl-some '< '(1 2 3) '(2 2 2)) ⏎
T

ここでは、1 と 2 の組み合わせ、2 と 2 の組み合わせ、3 と 2 の組み合わせで評価が行われます。