lambda式
lambda(ラムダ)式は,(名前のない)関数を記述するものである. たとえば,ある数に1を加える関数は,lambda式を使って,
(lambda (x) (+ x 1))と定義できる.lambda式を演算子として引数を与えれば
> ((lambda (x) (+ x 1)) 0) 1のように,関数の値を計算できる. これは,通常の関数の呼出しと全く同様である.
また(名前をもった)新しい関数の定義は,通常defineを用いて,
> (define (succ x) (+ x 1))などとするが,実はこれは
> (define succ (lambda (x) (+ x 1)))のように,lambda式によって記述される関数にdefineで名前を定義することの便 宜上の省略形式である.なお,一般にこのような便宜的な記法のことをsyntax sugar(文法上の砂糖)という.
lambda式の構造は以下の通り.
(lambda 形式引数 式1 式2 .... 式n)ここで形式引数は,以下のいずれかである.
- (仮引数1 仮引数2 … 仮引数n)
n個のパラメータ,仮引数1 … 仮引数nをとる. 関数に与えたパラメータの数がnと異なるとエラーになる.;; 次の定義は「(define (prec x) (- x 1))」と同じ > (define prec (lambda (x) (- x 1))) prec > (prec 2) 1 > (prec 1 2) ⇒ ERROR: Wrong number of arguments > (prec) ⇒ ERROR: Wrong number of arguments
- (仮引数1 仮引数2 … 仮引数n . 仮引数n+1) 0 <= n
仮引数1から仮引数nまでは,必須パラメータであり必ず与えなければならない. パラメータがn個より多く与えられた場合,仮引数n+1に余分なパラメータがリストとして渡される.;; 次の定義は「(define (f x y . z) (list x y z))」と同じ > (define f (lambda (x y . z) (list x y z))) f > (f 1 2 3 4 5) (1 2 (3 4 5)) > (f 1 2 3) (1 2 (3)) > (f 1 2) (1 2 ()) > (f 1) ⇒ ERROR: Wrong number of arguments
- 仮引数
(. 仮引数)と書いても同じ. つまり,2.の例で必須パラメータが0個の場合に相当する. 任意の数のパラメータを取ることができて,それらは一つのリストとして,関数に渡される. 例えば,組み込み関数listは次のように定義できる(ここでは,mylistという名前を使う).;; 次の定義は「(define (mylist . x) x)」と同じ > (define mylist (lambda x x)) mylist > (mylist 'a 'b '(1 2 3)) (a b (1 2 3)) > (mylist) ()
lambda式を使うと,いちいち関数に名前を定義しなくても,関数を別の関数の引 数に使うことができる.
;; 1変数関数f(x)について,f(a)+ ... + f(b)を計算する > (define (sum f a b) (if (> a b) 0 (+ (f a) (sum f (+ a 1) b)))) sum > (sum (lambda (x) (* x x)) 1 5) 55 ;; = 1^2 + 2^2 + 3^2 + 4^2 + 5^2 > (* 8.0 (sum (lambda (x) (/ 1 (* (- (* 4 x) 3) (- (* 4 x) 1)))) 1 100)) 3.13659268483882 ;; ⇒ゆっくりとπに収束する.
また関数を返す関数も定義できる.
> (define (succ-n n) (lambda (x) (+ x n))) succ-n > (succ-n 1) #<function> ;; (lambda (x) (+ x 1))という関数 > (+ ((succ-n 2) 1) ((succ-n 4) 2)) ;; (+ ((lambda (x) (+ x 2)) 1) ((lambda (x) (+ x 4)) 2)) 9
[参考]lambda式による再帰呼び出し関数
関数に名前を与えなくても再帰呼び出しを実現することはできる.
;; 2の累乗を計算する関数に引数10を与えた式 > (((lambda (f) ((lambda (m) (f (lambda (a) ((m m) a)))) (lambda (m) (f (lambda (a) ((m m) a)))))) (lambda (r) (lambda (n) (if (= n 0) 1 (* 2 (r (- n 1))))))) 10) 1024この表現に適宜名前を与えると,以下のようにもう少し分かりやすくなる.
> (define Y (lambda (f) ((lambda (m) (f (lambda (a) ((m m) a)))) (lambda (m) (f (lambda (a) ((m m) a))))))) > (define F (lambda (r) (lambda (n) (if (= n 0) 1 (* 2 (r (- n 1))))))) > ((Y F) 10) 1024ここで現れているYに対して,Fのような形で,再帰呼び出し関数の記述を与え てやれば,様々な再帰呼び出し関数を同様に表現することができる.
> (define D (lambda (r) (lambda (l) (if (null? l) '() (cons (* 2 (car l)) (r (cdr l))))))) > ((Y D) '(1 2 3)) (2 4 6)
上で定義した関数は,名前を与えれば,もちろん,ずっと簡潔に表現できる.
(define (pow2 n) (if (= n 0) 1 (* 2 (pow2 (- n 1))))) (define (double-list l) (if (null? l) '() (cons (* 2 (car l)) (double-list (cdr l)))))