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 をやります。