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+ycl の中の
(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 をやります。