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

Exercise 2.9

ここで扱う parse-expression は例示されている以下が対象という事で。

(define parse-expression
  (lambda (datum)
    (cond
      ((symbol? datum) (var-exp datum))
      ((pair? datum)
       (if (eqv? (car datum) 'lambda)
           (lambda-exp (caadr datum)
                       (parse-expression (caddr datum)))
           (app-exp
             (parse-expression (car datum))
             (parse-expression (cadr datum)))))
      (else
        (eopl:error 'parse-expression
                    "Invalid concrete syntax ~s" datum)))))

残ってないかな、と思ったら作って試験してました。ディレクトリをコピーして確認開始。
以下な試験を書いてみた。

(test* "parse (5)"
       *test-error*
       (parse-expression '(a b c)))
(test* "parse (6)"
       *test-error*
       (parse-expression '(lambda)))

で、試験の出力が以下(既存分含む

<parse-expression>-------------------------------------------------------------
test parse (1), expects (var-exp a) ==> ok
test parse (2), expects (lambda-exp x (var-exp x)) ==> ok
test parse (3), expects (app-exp (lambda-exp x (var-exp x)) (var-exp a)) ==> ok
test parse (4), expects #<error> ==> ok
test parse (5), expects #<error> ==> ERROR: GOT (app-exp (var-exp a) (var-exp b))
test parse (6), expects #<error> ==> ok
failed.
discrepancies found.  Errors are:
test parse (5): expects #<error> => got (app-exp (var-exp a) (var-exp b))

げ。parse (6) な試験がパスしとるぞ、っていいのか。ちょっと試験を以下にしてメセジを確認してみます。

(test* "parse (6)"
;;       *test-error*
       '(lambda)
       (parse-expression '(lambda)))

で試験の出力が以下。

test parse (5): expects #<error> => got (app-exp (var-exp a) (var-exp b))
test parse (6): expects (lambda) => got #<error "pair required, but got ()">

あまり複雑に考えないことにして、チェックが必要なのは以下?

  • lambda 式の場合、(length datum) は 3
  • ペアで lambda 式でない場合、(length datum) は 2

なんか微妙だなぁ。

微妙と言いつつ

以下の実装にて試験にパス。

(define parse-expression
  (lambda (datum)
    (cond
     ((symbol? datum) (var-exp datum))
     ((pair? datum)
      (if (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))
	  (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)))))

実は上記実装に辿り着くまえに以下なナチュラルをぶちカマしてたり。

(define parse-expression
  (lambda (datum)
    (cond
     ((symbol? datum) (var-exp datum))
     ((pair? datum)
      (if (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))
	  (app-exp
	   (cond ((eq? 2 (length datum))
		  (parse-expression (car datum))
		  (parse-expression (cadr datum)))
		 (else
		  (eopl:error 'parse-expression
			      "Invalid application argument ~s" datum))))))
     (else
      (eopl:error 'parse-expression
		  "Invalid concrete symtax ~s" datum)))))

以下なエラーがナニ。

test parse (3): expects (app-exp (lambda-exp x (var-exp x)) (var-exp a)) => got #<error "app-exp \"Expected ~s arguments but got ~s arguments.~n  Fields are: ~s ~n  Args are: ~s.\" 2 1 (rator rand) ((var-exp a))">

ボケっぷりが酷い。