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

天気は良いのですが波が高いはずなので外に遊びに行く気にならない。買い物してきて帰宅後に検討着手。

Exercise 2.11

expression を以下に修正。

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

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

で、unparse って以下で良いの?

(define unparse-expression
  (lambda (exp)
    (cases expression exp
	   (var-exp (id) id)
	   (lambda-exp (id body)
		       (list 'lambda (list id)
			     (unparse-expression body)))
	   (app-exp (rator rand)
		    (list (unparse-expression rator)
			  (unparse-expression rand)))
	   (lit-exp (datum) datum)
	   (primapp-exp (prim rand1 rand2)
			(list prim rand1 rand2)))))

以下の試験を追加してみました。

(test* "unparse (4)"
       1
       (unparse-expression '(lit-exp 1)))
(test* "unparse (5)"
       '(* x 3)
       (unparse-expression '(primapp-exp * (var-exp x) (lit-exp 3))))

で、結果が以下。

test unparse (4), expects 1 ==> ok
test unparse (5), expects (* x 3) ==> ERROR: GOT (* (var-exp x) (lit-exp 3))

わはは。なにやってんの。こうか。

	   (primapp-exp (prim rand1 rand2)
			(list prim 
			      (unparse-expression rand1) 
			      (unparse-expression rand2))))))

で、parse なんだけどどうしたものやら。+ と * 限定で以下?

(define parse-expression
  (lambda (datum)
    (cond
     ((number? datum) (lit-exp datum))
     ((symbol? datum) (var-exp datum))
     ((pair? datum)
      (cond ((eqv? (car datum) 'lambda)
	     (if (eq? 3 (length datum))
		 (lambda-exp (caadr datum)
			     (parse-expression (caddr datum)))
		 (eopl:error 'parse-expression
			     "Invalid lambda syntax ~s" datum)))
	    ((or (eq? (car datum) '+)
		 (eq? (car datum) '*))
	     (if (eq? 3 (length datum))
		 (primapp-exp (car datum)
			      (parse-expression (cadr datum))
			      (parse-expression (caddr datum)))
		 (eopl:error 'parse-expression
			     "Invalid primapp symtax ~s" datum)))
	     (else
	      (if (eq? 2 (length datum))
		  (app-exp
		   (parse-expression (car datum))
		   (parse-expression (cadr datum)))
		  (eopl:error 'parse-expression
			      "Invalid application argument ~s" datum)))))
     (else
      (eopl:error 'parse-expression
		  "Invalid concrete symtax ~s" datum)))))

なんか微妙にキタナい。以下の試験を追加したら

(test* "parse (7)"
       '(primapp-exp + (var-exp x) (lit-exp 3))
       (parse-expression '(+ x 3)))

試験失敗。

test parse (7), expects (primapp-exp + (var-exp x) (lit-exp 3)) ==> ERROR: GOT #<error "primapp-exp \"~n Bad ~a field (~s ~s) ==> #f.\" rand1 number? (var-exp x)">

とほほ。expression が微妙。正しくはこうか。

  (primapp-exp
   (prim symbol?)
   (rand1 expression?)
   (rand2 expression?)))

一応上記の試験にはパスしてます。

検討してるんですが、なんとなくさくっとオチた解が頭に出てこない。