[Prev]    [ Up ]    [Next]

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. (仮引数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
    
  2. (仮引数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
    
  3. 仮引数
    (. 仮引数)と書いても同じ. つまり,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)))))


[Prev]    [ Up ]    [Next]