リストの表記が (10 20 30) という形であることを学習すると、センスあるプログラマはすぐにこれが LISP の関数起動式にそっくりであることに気がつくでしょう。 なんてことはありません。 システムが評価していた関数 (+ 10 20) は、リストだったのです。 第一要素が関数名や特別式であることを表す記号で、それ以降の要素が引数として認識されていただけなのです。
手続き型言語では、あらゆる作業に独自の構文が割り当てられているため、関数を呼び出すには専用の関数起動式、変数に値を代入するには代入式を指定します。 しかし、LISP 言語はすべてはデータであるという基本概念が存在しています。 実行する関数式もまた、リストというデータで表現されているだけにすぎないのです。
この事実は、LISP 言語の多くの処理を実行時に動的に決定させることができるという可能性を表しています。 関数 (+ 10 20) や (set 'x 10) などの関数を実行するコマンドがすべてリストであるということは、これらを変数として保存することができるということを意味します。
(+ 10 20) を LISP システムに渡すと、システムはこのリストを評価して、その結果を表示していたのです。 list 関数や setq 特別式で作成したリストは、LISP に渡されたわけではなく、この関数が実行され、その結果が表示されていたのです。
では、リストを実行することができるのだろうか?という疑問が湧き上がってくるはずです。 LISP には組み込み関数でリストを評価する eval 関数があります。
eval form
この関数の form 引数には、評価する式を指定します。 LISP では式のことをしばしばフォームと呼び、リストのほかにも記号など LISP システムが評価できるあらゆるデータを指定することができます。
> (setq x 100) 100 > (eval 10) 10 > (eval x) 100
単純な数値や文字は一つのデータであり、それは単体でフォームになりえます。 数値の場合は単純に、そのデータそのものが結果となります。 次に記号 x を eval で評価していますが、その結果は変数 x に格納されている値となるでしょう。 単純にコマンドに数値や変数名を指定した場合と結果は同じです。
eval 関数にリストを渡せば、eval はリストを式として評価し、実行しようと試みます。 eval が実行するリストは、つまり第一要素が関数名などを表す記号で、その後は引数を表すデータの列ということになります。 ただし、setq や quote などの場合は、関数ではなく特別式として評価されます。
> (eval '(+ 10 20)) 30 > (eval '(setq x '(10 20 30))) (10 20 30)
このプログラムでは、最初のコマンドでは単純な (+ 10 20) というリストを評価しています。 LISP は、+ 関数によって 10 と 20 という値を加算した結果を返すでしょう。 次のコマンドでは、変数 x にリスト (10 20 30) を保存する setq 特別式を実行しています。 このリストを評価した後、記号 x を評価すれば正しく評価されていることを確認することができます。
リストを実行時に評価することができるという事実は、LISP 言語の可能性を大きく広げています。 これによって、コンパイラ言語にはできない、実行時のコマンド生成や、実行時のコマンドの変数化ということができるようになります。
> (setq add '(+ x y)) (+ X Y) > (setq x 10 y 20) 20 > (eval add) 30 > (setq x 100) 100 > (eval add) 120
この例で重要なのは (eval add) という部分です。 このリストは eval 関数に対してリストを保存する変数 add を評価して渡しています。 そのため、add に保存している内容や、add に関係する変数が変化すると、それによって eval の結果も異なってくることがわかります。 変数にリストを保存し、その変数の内容を eval で評価するようなプログラムを作れば、実行時に実行するコードを挿げ替えるという手法が比較的容易に行うことができます。