EoPL reading (66) 2.2 An Abstraction for Inductive Data Type

うーん、迷走気味。現時点にて parse な試験で問題発生中。

test unparse (4), expects (lambda (x) (f x y)) ==> ERROR: GOT #<error "wrong number of arguments for #<closure (unparse-expression unparse-expression)> (required 2, got 3)">
test unparse (5), expects (lambda (x) (x)) ==> ERROR: GOT #<error "wrong number of arguments for #<closure (unparse-expression unparse-expression)> (required 2, got 1)">

実装を控え。まず、expression.scm から

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

(define list-of
  (lambda (pred)
    (lambda (val)
      (or (null? val)
	  (and (pair? val)
	       (pred (car val))
	       ((list-of pred) (cdr val)))))))

(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
   (ids (list-of symbol?))
   (body expression?))
  (app-exp
   (rator expression?) 
   (rands (list-of expression?))))

次は parse.scm

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

(define unparse-expression
  (lambda (exp)
    (cases expression exp
	   (lit-exp (datum) datum)
	   (var-exp (id) id)
	   (if-exp (test-exp true-exp false-exp)
		   (list 'if test-exp true-exp false-exp))
	   (lambda-exp (ids body)
		       (list 'lambda ids
			     (unparse-expression body)))
	   (app-exp (rator rands)
		    (list (unparse-expression rator)
			  (unparse-expression rands))
		    ))))

(define parse-expression
  (lambda (datum)
    (cond
     ((number? datum) (lit-exp datum))
     ((symbol? datum) (var-exp datum))
     ((pair? datum)
      (cond ((eqv? (car datum) 'lambda)
	     (lambda-exp (cadr datum)
			 (parse-expression (caddr datum))))
	    ((eqv? (car datum) 'if)
	     (if-exp (cadr datum) (caddr datum) (cadddr datum)))
	    (else
	      (let f ((rslt '(app-exp)) (datum datum))
		(if (null? datum)
		    rslt
		    (f (append rslt (list (parse-expression (car datum))))
		       (cdr datum)))))))
     (else
      (eopl:error 'parse-expression
		  "Invalid concrete symtax ~s" datum)))))

あと、parse の試験も以下に。

(use gauche.test)

(add-load-path ".")
(load "define-datatype")
(load "expression")
(load "occurs-free")
(load "parse")

(test-start "parse")
(test-section "unparse-expression")
(test* "unparse (1)"
       'a
       (unparse-expression '(var-exp a)))
(test* "unparse (2)"
       '(lambda (x) x)
       (unparse-expression '(lambda-exp (x) (var-exp x))))
(test* "unparse (3)"
       '((lambda (x) x) a)
       (unparse-expression '(app-exp (lambda-exp (x) (var-exp x)) (var-exp a))))
(test* "unparse (4)"
       '(lambda (x) (f x y))
       (unparse-expression '(lambda-exp (x) (app-exp (var-exp f) (var-exp x) (var-exp y)))))
(test* "unparse (5)"
       '(lambda (x) (x))
       (unparse-expression '(lambda-exp (x) (app-exp (var-exp x)))))
(test* "unparse (6)"
       '(lambda (x y z) x)
       (unparse-expression '(lambda-exp (x y z) (var-exp x))))
(test* "unparse (7)"
       '(lambda () x)
       (unparse-expression '(lambda-exp () (var-exp x))))

(test-section "parse-expression")
(test* "parse (1)"
       '(var-exp a)
       (parse-expression 'a))
(test* "parse (2)"
       '(lambda-exp (x) (var-exp x))
       (parse-expression '(lambda (x) x)))
(test* "parse (3)"
       '(app-exp (lambda-exp (x) (var-exp x)) (var-exp a))
       (parse-expression '((lambda (x) x) a)))
(test* "parse (4)"
       '(lit-exp 5)
       (parse-expression 5))
(test* "parse (5)"
       *test-error*
       (parse-expression "a"))
(test* "parse (6)"
       '(app-exp (var-exp a) (var-exp b) (var-exp c))
       (parse-expression '(a b c)))
(test* "parse (7)"
       '(app-exp (lambda-exp (x) (app-exp (var-exp +) (var-exp x) (var-exp x))) (var-exp a))
       (parse-expression '((lambda (x) (+ x x)) a)))
(test* "parse (8)"
       '(lambda-exp (x) (app-exp (var-exp x)))
       (parse-expression '(lambda (x) (x))))

(test-end)

なんとなく見えてるのは

  • (app-exp (var-exp f) (var-exp x) (var-exp y)) は引数 3 つなので引数二つな app-exp の呼び出しに対応不可能
  • (app-exp (var-exp x)) は引数 1 つなので (ry

という事。だったら app-exp な分岐を以下にしたらどうか、とトライしてみると

discrepancies found.  Errors are:
test unparse (1): expects a => got #<error "proper list required, but got (rator . rands)">
test unparse (2): expects (lambda (x) x) => got #<error "proper list required, but got (rator . rands)">
test unparse (3): expects ((lambda (x) x) a) => got #<error "proper list required, but got (rator . rands)">
test unparse (4): expects (lambda (x) (f x y)) => got #<error "proper list required, but got (rator . rands)">
test unparse (5): expects (lambda (x) (x)) => got #<error "proper list required, but got (rator . rands)">
test unparse (6): expects (lambda (x y z) x) => got #<error "proper list required, but got (rator . rands)">
test unparse (7): expects (lambda () x) => got #<error "proper list required, but got (rator . rands)">

って叱られる。可変長引数にマッチ可能な syntax-rules の書き方がどうか、が分かれば問題解決なのでしょうか。色々試験してみているんですが、途中中断
ってか今日はこのまま終了。

追記

昨晩、エントリ投入途上で寝落ちしてました。ちなみに盛り込んだ実装は以下になります。

	   (app-exp (rator rands)
;;		    (list (unparse-expression rator)
;;			  (unparse-expression rands))
		    (append (list (unparse-expression rator))
			    (if (pair? rands)
				(unparse-expression rands)
				(if (null? rands)
				    '()
				    (list rands)))))
			      

解決の糸口が全く見えてません。いったん最初から見直した方が良さげ。