関数

関数は、単にリストの最初の要素がlambdaであるようなlambda書式によって 表現される。 もしlambda書式がdefunを使ってsymbolを定義するとき、 グローバル関数名として参照することができる。 lambda書式は、次の文法で与えられる。


 (lambda ({var}* 
)}*]

) $ \vert$ ((keyword var) [initform])}*
]
)}*])
{declaration}*
{form}*)

ここにEXPR,LEXPR,FEXPRなどのような型の関数はない。 関数への引数は、いつもその関数を実行する前に評価される。 受ける引数の数は、lambda-listによって決定される。 lambda-listは、lambda書式のためにパラメータの列を記す。

&optional, &rest, &key &aux はそれぞれ、lambda-list のなかに特殊な意味を持っていて、これらのsymbolは、変数名として使用 することはできない。 &optionalや&keyパラメータのsupplied-p変数は、サポートされていない。

lambda書式は、普通のリストデータと区別できないため、 function特殊書式を用いて、インタプリタやコンパイラに関数として 認識するように知らせなければならない。 1functionは、関数の上に環境を固定するために重要である。 そのため、すべてのローカル変数はその関数が違ったローカルスコープの他の関数を 通ってきたとしてさえ、アクセスすることができる。 次のプログラムは、letsumがlambda書式の中に見えるため、 インタプリタとコンパイル後のどちらも何もしない。

(let ((x '(1 2 3)) (sum 0))
  (mapc '(lambda (x) (setq sum (+ sum x))) x))

予想した結果が得られるためには、次のように書くべきである。

(let ((x '(1 2 3)) (sum 0))
   (mapc #'(lambda (x) (setq sum (+ sum x))) x ))

#'は、functionの略語である。 すなわち、#'(lambda (x) x)(function (lambda (x) x))と同等である。 ここは、funarg問題と呼ばれる別の例を示す。

(defun mapvector (f v)
    (do ((i 0 (1+ i)))
       ((>= i (length v)))
       (funcall f (aref v i))))
(defun vector-sum (v)
    (let ((i 0))
       (mapvector #'(lambda (x) (setq i (+ i x))) v)
       i))
(vector-sum #(1 2 3 4)) --> 10

EusLispのclosureは、不定な大きさを持つことができない。 すなわち、closureはその外側の大きさで可能な大きさまで持つことができる。 これはclosureが'generators'のプログラミングのために使用されないことを意味する。 次のプログラムは何もしない。

(proclaim '(special gen))
(let ((index 0))
   (setq gen #'(lambda () (setq index (1+ index)))))
(funcall gen)

しかしながら、その同じ目的がオブジェクト指向プログラミングで実現できる。 なぜなら、オブジェクトはそれ自身の固定変数を持つことができるためである。

(defclass generator object (index))
(defmethod generator
 (:next () (setq index (1+ index)))
 (:init (&optional (start 0)) (setq index start) self))
(defvar gen (instance generator :init 0))
(send gen :next)


2016-04-05