lookup-variable-value を書き換えてみる

このあたり、C で書けないかを検討してみます。とりあえず手続き定義の中で define しているナニを書き換えてみる方向で。
元の定義は以下。

(define (lookup-variable-value var env)
  (define (env-loop env)
    (define (scan vars vals)
      (cond ((null? vars)
	     (env-loop (cdr env)))
	    ((eq? var (car vars))
	     (car vals))
	    (else (scan (cdr vars) (cdr vals)))))
    (if (eq? env '())
	(error "Unbound variable" var)
	(let ((frame (car env)))
	  (scan (car frame)
		(cdr frame)))))
  (env-loop env))

ちょっと書き換えしてますが、中から順に書き換えてみます。まず一番中から set! してみる方向で。

(define (lookup-variable-value var env)
  (define (env-loop env)
    (set! scan
	  (lambda (vars vals)
	    (cond ((null? vars)
		   (env-loop (cdr env)))
		  ((eq? var (car vars))
		   (car vals))
		  (else (scan (cdr vars) (cdr vals))))))
    (if (eq? env '())
	(error "Unbound variable" var)
	(let ((frame (car env)))
	  (scan (car frame)
		(cdr frame)))))
  (env-loop env))

次。

(define (lookup-variable-value var env)
  (set! env-loop
	(lambda (env)
	  (set! scan
		(lambda (vars vals)
		  (cond ((null? vars)
			 (env-loop (cdr env)))
			((eq? var (car vars))
			 (car vals))
			(else (scan (cdr vars) (cdr vals))))))
	  (if (eq? env '())
	      (error "Unbound variable" var)
	      (let ((frame (car env)))
		(scan (car frame)
		      (cdr frame))))))
  (env-loop env))

ってか試しに fact を作ろうとしてどハマり。最初はこんな感じで書いてたんですが

(define fact
  (lambda (x)
    (set! f 
	  (lambda (x r)
	    (if (null? x)
		r
		(f (cdr x) (* (car x) r))))))
  (f x 1))

f 知らん、と言われ叱られる。

gosh> (fact '())
*** ERROR: symbol not defined: #<identifier user#f>

一晩寝て起きてヒリ出したのが以下。

(define fact 
  (lambda (x)
    (let ((f '()))
      (set! f 
	    (lambda (x r)
	      (if (null? x)
		  r
		  (f (cdr x) (* (car x) r)))))
      (f x 1))))

let は lambda の syntax suger って SICP にはある。という事は上記は以下のように書けるの?

(define fact
  (lambda (x)
    ((lambda (f)
       (set! f 
	     (lambda (x r)
	       (if (null? x)
		   r
		   (f (cdr x) (* (car x) r))))))
     '())
    (f x 1)))

試してみます。

gosh> (fact '(1 2 3))
*** ERROR: unbound variable: f

駄目ッスか。あ、これはケツの f の呼び出しで、ですね。ってコトは

(define fact
  (lambda (x)
    ((lambda (f)
       (set! f 
	     (lambda (x r)
	       (if (null? x)
		   r
		   (f (cdr x) (* (car x) r)))))
       (f x 1))
     '())))

こうか。ちょっとリハビリ必要らしい。lookup_variable-value もこれ式で書く必要がありそげ。書き直してみると以下?

(define (lookup-variable-value var env)
  (define (env-loop env)
    (define scan
	((lambda (scan-inner)
	   (set! scan-inner
		 (lambda (vars vals)
		   (cond ((null? vars)
			  (env-loop (cdr env)))
			 ((eq? var (car vars))
			  (car vals))
			 (else (scan-inner (cdr vars) (cdr vals)))))))
	 '()))
    (if (eq? env '())
	(error "Unbound variable" var)
	(let ((frame (car env)))
	  (scan (car frame)
		(cdr frame)))))
  (env-loop env))

大丈夫かな。一応動くみたい。

gosh> (lookup-variable-value 'x '(((x y) . (1 2))))
1

もう一枚皮をメクッてみます。

(define (lookup-variable-value var env)
  (define env-loop
    ((lambda (env-loop-inner)
      (define scan
	((lambda (scan-inner)
	   (set! scan-inner
		 (lambda (vars vals)
		   (cond ((null? vars)
			  (env-loop (cdr env)))
			 ((eq? var (car vars))
			  (car vals))
			 (else (scan-inner (cdr vars) (cdr vals)))))))
	 '()))
      (set! env-loop-inner
	    (if (eq? env '())
		(error "Unbound variable" var)
		(let ((frame (car env)))
		  (scan (car frame)
			(cdr frame))))))
     '()))
  (env-loop env))

だんだんワケワカらなくなってきてます。

gosh> (lookup-variable-value 'x '(((x y) . (1 2))))
*** ERROR: invalid application: (1 (((x y) 1 2)))

リトライ。落ち着け。

(define (lookup-variable-value var env)
  (define env-loop
    ((lambda (env-loop-inner)
      (define scan
	((lambda (scan-inner)
	   (set! scan-inner
		 (lambda (vars vals)
		   (cond ((null? vars)
			  (env-loop (cdr env)))
			 ((eq? var (car vars))
			  (car vals))
			 (else (scan-inner (cdr vars) (cdr vals)))))))
	 '()))
      (set! env-loop-inner
	    (lambda (env)
	      (if (eq? env '())
		  (error "Unbound variable" var)
		  (let ((frame (car env)))
		    (scan (car frame)
			  (cdr frame)))))))
     '()))
  (env-loop env))

これで良いはず。

gosh> (lookup-variable-value 'x '(((x y) . (1 2))))
1

本当かなぁ。で、ここまで書き換えれたら C にって手筈だったんですがどうも微妙。