Exercise 2.11 (2)

またまたちょっとだけ。昨日の朝の続き。
問題点としては以下な模様。

  • 渡す lambda な S 式は expression な形になっている必要あり
    • parse すれば良いのか
  • primapp-exp を expression.scm に追加
  • fresh_id.scm も修正必要
  • lexical-address と expression が混在
    • fresh_id.scm は expression を使用
    • lambda-calculus-subst.scm は expression を使用
    • occurs-free.scm で lexical-address 使用

あら、lexical-address を使っていない occurs-free はどっかにないかな。

無かったので

でっちあげた。以下。

(add-load-path ".")
(load "expression")

(define occurs-free?
  (lambda (var exp)
    (cases lexical-address exp
	   (lit-exp (datum) #t)
	   (var-exp (id) (eqv? var id))
	   (if-exp (test-exp true-exp false-exp)
		   (or (occurs-free? var test-exp)
		       (occurs-free? var true-exp)
		       (occurs-free? var false-exp)))
	   (lambda-exp (id body)
		       (and (not (eqv? id var))
			    (occurs-free? var body)))
	   (app-exp (rator rand)
		    (or (occurs-free? var rator)
			(occurs-free? var rand))))))

本当かなぁ。
で次。expression.scm を以下に。

(add-load-path "../../define-datatype")
(load "define-datatype")

(define-datatype expression expression?
  (lit-exp
   (datum number?))
  (var-exp
   (id symbol?))
  (if-exp
   (test-exp expression?)
   (true-exp expression?)
   (false-exp expression?))
  (lambda-exp
   (id symbol?)
   (body expression?))
  (app-exp
   (rator expression?)
   (rand expression?))
  (primapp-exp
   (prim symbol?)
   (rand1 expression?)
   (rand2 expression?)))

これも試験必要ですね。そして fresh-id.scm も以下に。

(add-load-path ".")
(load "expression")

(use srfi-1)

(define enum-filter-vars
  (lambda (exp)
    (delete-duplicates (flatten (enum-vars exp)))))

(define (flatten xs)
  (cond ((null? xs) '())
	((pair? xs) (append-map flatten xs))
	(else
	 (list xs))))

(define all-ids
  (lambda (exp)
    (delete-duplicates (flatten (enum-ids exp)))))

(define enum-ids
  (lambda  (exp)
    (cases expression exp
      (var-exp (id) id)
      (lambda-exp (id body)
        (cons id (all-ids body)))
      (app-exp (rator rand)
        (cons (all-ids rator) (all-ids rand)))
      (priapp-exp (prim rand1 rand2)
	(cons (all-ids rand1) (all-ids rand2))))))
		  

(define fresh-id
  (lambda (exp s)
    (let ((syms (all-ids exp)))
      (letrec ((loop (lambda (n)
		       (let ((sym (string->symbol
				   (string-append s
						  (number->string n)))))
			 (if (memv sym syms) (loop (+ n 1)) sym)))))
	(loop 0)))))

こいつらどこかに試験があるはずなのでサルベージしてみます。

  • occurs-free は Ex.2.8 で試験を書いている
  • fresh-id は Ex.2.10 で試験を書いている
  • expression の試験は無いのでスルー

で、上記試験はパスしてる風なのですが、肝心の lambda-calculus-subst な試験がパスせず。これはまた別途、ってことになるのかどうかorz
しかも occurs-free? な試験が微妙。微妙なのはコピィ元だったりしてorz

微妙なのは

expression な定義だったりするのかも、と思いはじめていたりしてます。現状以下。

(add-load-path "../../define-datatype")
(load "define-datatype")

(define-datatype expression expression?
  (lit-exp
   (datum number?))
  (var-exp
   (id symbol?))
  (if-exp
   (test-exp expression?)
   (true-exp expression?)
   (false-exp expression?))
  (lambda-exp
   (id symbol?)
   (body expression?))
  (app-exp
   (rator expression?)
   (rand expression?))
  (primapp-exp
   (prim (lambda (x) (or (eqv? '+ x) (eqv? '* x))))
   (rand1 expression?)
   (rand2 expression?)))

lambda-calculus-subst の試験が以下で

(use gauche.test)
(add-load-path ".")
(load "parse-expression")
(load "lambda-calculus-subst")

(test-start "lambda-calculus-subst")
(test-section "lambda-calculus-subst")
(test* "occurs-bound"
       '(lambda-exp (p0) 
		    (primapp-exp + 
				(var-exp p0) 
				(primapp-exp * (var-exp p) (lit-exp 3))))
       (lambda-calculus-subst (parse-expression '(lambda (p) (+ p x)))
			      (parse-expression '(* p 3))
			      'x))

(test* "occurs-free"
       '(lambda-exp (q) (primapp-exp + 
				     (var-exp q) 
				     (primapp-exp * (var-exp p) (lit-exp 3))))
       (lambda-calculus-subst (parse-expression '(lambda (q) (+ q x)))
			      (parse-expression '(* p 3))
			      'x))

(test-end)

以下なエラーが出てます。備忘まで。

test occurs-bound, expects (lambda-exp (p0) 
                                       (primapp-exp + (var-exp p0) 
                                                    (primapp-exp * (var-exp p) (lit-exp 3)))) 
  ==> ERROR: GOT #<<error> "primapp-exp \"Expected 3 arguments but got 2 arguments.
      Fields are: (prim rand1 rand2) 
      Args are: ((var-exp p) (primapp-exp * (var-exp p) (lit-exp 3)))"

ぐぬぬ。