EoPL reading (119) 2.3 Representation Strategies for Data Types

とりあえず、鍛錬をこつこつ続ける事に。高等数学きちんとヤッてないので scheme 使って計算云々な役立て方をイメージするのが微妙なんでしょうか。
それは良いとして Ex. 2.24 ですが誤読していた模様?
procedual なナニで言うと以下なカンジ?

(define empty-subst
  (lambda ()
    (lambda (sym)
      sym)))

(define apply-subst
  (lambda (s i)
    (s i)))

(define extend-subst
  (lambda (i t s)
    (lambda (sym)
      (if (eqv? sym i)
	  t
	  (apply-subst s sym)))))

問題の記述によれば

  • (empty-subst) は which binds its argument to a variable term of its argument とあるので引数を var-term にして戻せば良い模様
  • apply-subst は which returns the value of symbol i in substitutions s とあるので s に i を渡せば良い?
  • extend-subst は symbol i is assciated with term t 以外は s と同様、みたいな記述なので単純に extend すれば良い

そのまま戻す、というあたりを誤読というかそもそも読み切れていなかった模様。なるほどこれだとオブジェクトがどーゆーモノかをイメージできますな。

試験書いた

以下。

(use gauche.test)

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

(test-start "substitution")
(test-section "empty-subst")
(test* "((empty-subst) 'a) returns a"
       'a
       ((empty-subst) 'a))

(test-section "apply-subst")
(test* "(apply-subst (empty-subst) 'a) returns a"
       'a
       (apply-subst (empty-subst) 'a))

(test-section "extend-subst")
(test* "(apply-subst (extend-subst 'a '(x y) (empty-subst)) 'a) returns '(x y)"
       '(x y)
       (apply-subst (extend-subst 'a '(x y) (empty-subst)) 'a))

(test* "(apply-subst (extend-subst 'a '(x y) (empty-subst)) 'b) returns b"
       'b
       (apply-subst (extend-subst 'a '(x y) (empty-subst)) 'b))

(test-end)

これを元にabstract syntax tree representation なソレを書いてみる。とりあえず。define-datatype.scm および term.scm を新たに作成したディレクトリにコピィ。
で、以下がでっち上がる。

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

(define-datatype substitution substitution?
  (empty-subst-rec)
  (extended-subst-rec
   (id symbol?)
   (term term?)
   (sub substitution?)))		 

(define empty-subst
  (lambda ()
    (empty-subst-rec)))

(define extend-subst
  (lambda (i t s)
    (extended-subst-rec i t s)))

(define apply-subst
  (lambda (s i)
    (cases substitution s
	   (empty-subst-rec ()
			    (var-term i))
	   (extended-subst-rec (id term sub)
			       (if (eqv? i id)
				   term
				   (apply-subst sub i))))))

直上の試験を若干改変。ちなみに define-datatype にて extended-subst_rec と定義してたお陰でハマりました。

(use gauche.test)

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

(test-start "substitution")
(test-section "empty-subst")
(test* "(empty-subst) returns (empty-subst-rec)"
       '(empty-subst-rec)
       (empty-subst))

(test-section "apply-subst")
(test* "(apply-subst (empty-subst) 'a) returns (var-term a)"
       '(var-term a)
       (apply-subst (empty-subst) 'a))

(test-section "extend-subst")
(test* "(apply-subst (extend-subst 'a  '(app-term ((var-term x) (var-term y))) (empty-subst)) 'a) returns '(app-term ((var-term x) (var-term y)))"
       '(app-term ((var-term x) (var-term y)))
       (apply-subst (extend-subst 'a '(app-term ((var-term x) (var-term y))) (empty-subst)) 'a))

(test* "(apply-subst (extend-subst 'a '(app-term ((var-term x) (var-term y))) (empty-subst)) 'b) returns (var-term b)"
       '(var-term b)
       (apply-subst (extend-subst 'a '(app-term ((var-term x) (var-term y))) (empty-subst)) 'b))

(test-end)

見にくい。ここまでできたらあとは楽ですな。app-term だったら中のリストに subst-in-term を適用するナニ。

(define subst-in-term
  (lambda (t s)
    (cases term t
	   (var-term (id) (apply-subst s id))
	   (constant-term (datum) (constant-term datum))
	   (app-term (terms)
		     (let f ((rslt '()) (terms terms))
		       (if (null? terms)
			   (app-term rslt)
			   (f (append rslt (list (subst-in-term (car terms) s)))
			      (cdr terms))))))))

試験が以下。

(use gauche.test)

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

(test-start "subst-in-term")
(test-section "subst-in-term")
(test* "(subst-in-term (constant-term 1) (empty-subst)) returns"
       '(constant-term 1)
       (subst-in-term '(constant-term 1) (empty-subst)))

(test* "(subst-in-term (var-term a) (empty-subst)) returns"
       '(var-term a)
       (subst-in-term '(var-term a) (empty-subst)))

(test* "(subst-in-term (app-term ((var-term a) (var-term b))) (empty-subst)) returns"
       '(app-term ((var-term a) (var-term b)))
       (subst-in-term '(app-term ((var-term a) (var-term b))) (empty-subst)))

(test* "(subst-in-term (app-term ((var-term a) (var-term b))) (extend-subst 'a '(var-term z) (empty-subst))) returns"
       '(app-term ((var-term z) (var-term b)))
       (subst-in-term '(app-term ((var-term a) (var-term b))) 
		      (extend-subst 'a '(var-term z) (empty-subst))))

(test-end)

若干試験が足りてない気がしますがスルー。subst-in-terms はリキが残ってれば、という事にて。