LISPの続き

Menu Menu


変数のScope/Extent

変数の字義的な定義の場所と、それを使える場所の範囲
    Scope
    1 ]=>  (let ((a 1)(b 3)) (set!  a 3) ( + a b))
    ;Value: 6
    1 ]=> a
    ;Unbound variable: a

変数がメモリ上に取られる場所の寿命
    Extent
    (define (sub x) 
	(let ((a 1)(b 3)) 
	    (set! x (+ x 3)) (+ (+ x a) b))))


関数を返す関数

    1 ]=> (lambda (x) ( + x 3))
    ;Value 12: #[compound-procedure 12]
    1 ]=> ((lambda (x) ( + x 3)) 3)
    ;Value: 6
    1 ]=> (define add (lambda (x) ( + x 3)))
    ;Value: add
    1 ]=> add 
    ;Value 13: #[compound-procedure 13 add]
    1 ]=> (add 4)
    ;Value: 7

高階関数

    (define (cl x)
       (lambda (y) (+ x y)))
    1 ]=> cl
    ;Value 14: #[compound-procedure 14 cl]
    1 ]=> (cl 4)
    ;Value 15: #[compound-procedure 15]
    1 ]=> ((cl 4) 7)
    ;Value: 11

(+ x y) ってのは、高階関数を使って、((+ x) y)のように分解できる。(Curry 化)

Lambda calcurus は、もともと、高階関数を取り扱う手法だった。

    λx.λy.x+y

cl の中の
       (lambda (y) (+ x y))

の x ってのは、どこかに生き残っている。

x の Extent がある。cl は、4 を中に持っている。

    cl ってのは、関数と、そこに入っている変数の値の組
    後者を環境(Environment)と言うことがある。

こういう環境と関数の組を、closure (閉包)と呼びます。

(Java にもありますね。でも、そのときには、final とかを使う)


問題6.1

関数を引数で渡し、それを二回作用させる関数を返す関数

例えば、2を足す関数を与えると、4を足す関数を返す。

    (define add4 (twice (lambda (x)(+ x 2))))

とすると、
    (add4 1)

で、5 が返る。


Back quote

    1 ]=> '(a b c d)
    ;Value 11: (a b c d)
    1 ]=> (define x '(a b c d))
    ;Value: x
    1 ]=> x
    ;Value 12: (a b c d)
    1 ]=> `(a b c)
    ;Value 13: (a b c)
    1 ]=> `(a b c x)
    ;Value 14: (a b c x)
    1 ]=> `(a b c ,x)
    ;Value 15: (a b c (a b c d))

Shell でも同じようなことが出来た。

    #!/bin/sh
    x=kono
    cat <<ECHOECHO
      1
      $x
      3
    ECHOECHO


Macro


Generic Programming


Eval, Apply


Meta Circular Interpreter

Interpreter を自分で作る。

    (if (eq? (car e) '+)
        (+ (car (cdr e)) (car (cdr (cdr e)))))
  (define (my-eval e)
    (cond ((eq? (first e) '+)
	    (+ (second e) (third e)))
	((eq? (first e) '-)
	    (- (second e) (third e)))
	((eq? (first e) '*)
	    (* (second e) (third e)))
	((eq? (first e) '/)
	    (/ (second e) (third e)))))

これではだめで..

  (define (my-eval e)
    (cond 
	((number? e) e)
	((eq? (first e) '+)
	    (+ (my-eval (second e)) (my-eval (third e))))
	((eq? (first e) '-)
	    (- (my-eval (second e)) (my-eval (third e))))
	((eq? (first e) '*)
	    (* (my-eval (second e)) (my-eval (third e))))
	((eq? (first e) '/)
	    (/ (my-eval (second e)) (my-eval (third e))))))

こういう風にどんどん進めていくと、scheme の完全なinterpreter を作ることが出来る。


Closure と Object と Iterator

    (define (it i)
	(define (it1 i j)
	    (if (= i 0) ()
		(cons j (it1 (- i 1) (+ j 1)))))
        (it1 i 0))
    (define (sum l)
        (if (null? sum) 0
            (+ (car l) (sum (cdr l)))))

これで、

     (sum (it 10))

のようにしたい。


さらに興味があれば...

defstruct, continuation

おまけ

来週は、AppleScript と Squeak をやります。


Shinji KONO / Mon Jul 8 19:12:07 2013