言語

LISP メモ

◇ 1. ラムダ(lambda)式

 数式は、単にf(x)と表現されているだけでは、それが関数をあらわしているのか、 あるいは関数値を表しているのか区別がつかない。なぜなら変数のxが仮引数で あればf(x)は関数になり、実引数であれば値の決まった関数値になるからである。 (変数を数学的に束縛変数と自由変数に分けて説明する方法もあるが、ここではプログラミング の世界の仮引数、実引数、局所変数、大域変数などで説明する。)

 lispではlambda式で関数を定義することができる。
たとえば、(+ x y)のような加算の式において、xとyが仮引数であること明示的に表す にはlambda (x y)と表現すればよい。
そうすると、xとyの加算の関数は全体をカッコでまとめたリスト形式で

          (lambda (x y) (+ x y)) 
のように表せる。

 この関数に実引数として、1と2を与えるには次のようなリスト形式にすればよい。

        ((lambda (x y) (+ x y)) 1 2) 
このリストを評価(eval)すれば関数値として3が返ってくる。




◇ 2. 関数に名前をつける

 (lambda (x y) (+ x y)) を次のようにplusという変数に代入すれば、 形式的にplusという名前をつけたことになる。

        (setq plus '(lambda (x y) (+ x y)))

 このplusに実引数の1と2を与えて実行するには、次のようなfuncallやapplyを 使かったリスト形式にすればよい

        

             (funcall plus 1 2) 



             (apply plus '(1 2)) 



             (apply plus 1 '(2)) 



             (apply plus 1 2 ()) 



             (apply plus 1 2 nil) 

 以上のいづれのリストも評価(eval)すると返り値は3になる。




◇ 3. 関数の定義

 最初に関数を定義する記号として = を使うことにする。

 たとえば、関数の名前plusを(lambda (x y) (+ x y))で定義する場合、通常の数学 などで使うinfix記法にしたがえば、次のようになるが、

         plus = (lambda (x y) (+ x y)) 
 lispで使うリスト形式のprefix記法を使うとつぎのようになる。
         (= plus (lambda (x y) (+ x y))) 

 関数を定義する記号の = を文字のdefineに置き換えると次のようになる。

         (define plus (lambda (x y) (+ x y))) 

 現在の代表的なlispでは、functionをdefineする意味でdefunを使って、次の ように簡単にした表記法が主流である。

         (defun plus (x y) (+ x y)) 
 このdefunで始まるリストを評価すると、仮引数をxおよびyとした加算の関数が plus という名前で定義される。

 この定義された plus 関数に実引数の1と2を与えるリスト形式は次のようになる。

         (plus 1 2) 
 このリストを評価すると返り値は3になる。




◇ 4. defun定義関数とlambda式関数の違い

a. 変数やブロックのスコープがdefun定義関数では途絶えるがlambda式関数では 途絶えない。

 たとえば、インクリメント(1を加算)する関数をdefunで次のように定義しておき、


          (defun incr ()

              (setq x (1+ x)))

 つぎのようにletでxを0に初期化しておいて、defunで定義したincr関数を適用 してもxの値はインクリメントされない。

         > (let ((x 0))

              (incr)

               x)

         => 0

 上の式で、 > はリスプ・インタプリタ―のプロンプトを表し、 => は評価した返り値を示す ものとする。
 上式が示すようにletで初期化したxはincrへ入れず、そのスコープが途絶えている。

 次のようにlamda式でインクリメントする関数を作ったばあいは、letで0に初期化した xの値が1にインクリメントされる。つまり、スコープが途絶えていないことを示す。


          > (let ((x 0))

               ((lambda () (setq x (1+ x))))

                x)

          => 1

b. defun定義関数のまわりにはリスプシステムが自動的にブロックを用意するが、 lambda式のまわりにはブロックが用意されない。

 たとえば、ブロックから脱出する関数をexitという名前で次のように定義する。


           (defun exit ()

              (return-from exit 0))

 このexitの返り値をブロック内でインクリメントする次のような式を評価すると 期待どおりインクリメントされた値が得られる。

           > (block exit

               (1+ (exit)))

           => 1

しかしながら、lambda式のばあいは、いきなりblockの外へ出てしまう。

           > (block exit

               (1+ ((lambda () (return-from exit 0)))))

           => 0




◇ 5. 記号関数とfunction式

準備中




◇ 6. グローバル関数

準備中




◇ 7. ローカル関数

準備中




◇ 8. クロージャー

準備中




言語


言語の目次へ戻る

ホームに戻る