SICP 読み (32) 2.2.4 例: 図形言語

最初、frame と painter の関係についての理解が微妙だった。単位方形 (unit square) についても同様。で、こいつらの理解ができんと駄目なのが分かってたので、図形を表示させる前になんとか理解しやすい試験がしたいな、と試行錯誤。
まず、gaunit で何とかならぬのか、と色々検討するも、元の for-each 使った実装では、どーにもならない事が分かる。図形描画なので副作用なソレ中心がデフォルトだよね、と言いつつペインタを試験用な stub にしてしまう。

(define (segments->painter segment-list)
  (lambda (frame)
    (map
     (lambda (segment)
       (draw-line
	((frame-coord-map frame) (start-segment segment))
	((frame-coord-map frame) (end-segment segment))))
     segment-list)))

for-each じゃなくって map にしちまえばリストが返される。しかも draw-line は以下。

(define (draw-line s e)
  (list s e))

これで draw-line に渡る値がチェックできる、とゆー事で試験を書いた。以下のような感じ。

(define-test-case "2.49-a (1)"
  ("2.49-a (1)"
   (let ((l1 (make-segment (make-vect 0.0 0.0)
			   (make-vect 0.0 1.0)))
	 (l2 (make-segment (make-vect 0.0 0.0)
			   (make-vect 1.0 0.0)))
	 (l3 (make-segment (make-vect 1.0 0.0)
			   (make-vect 1.0 1.0)))
	 (l4 (make-segment (make-vect 0.0 1.0)
			   (make-vect 1.0 1.0))))
     (let ((p (segments->painter (list l1 l2 l3 l4))))
       (let ((f (make-frame (make-vect 2.0 2.0)
			    (make-vect 2.0 0.0)
			    (make-vect 0.0 2.0))))

	 (assert-equal 2.0 (xcor-vect (start-segment (car (p f)))))
	 (assert-equal 2.0 (ycor-vect (start-segment (car (p f)))))
	 (assert-equal 2.0 (xcor-vect (end-segment (car (p f)))))
	 (assert-equal 4.0 (ycor-vect (end-segment (car (p f)))))
)))))

ちなみに上記の試験は l1 の試験。(car (p f)) に l1、(cadr (p f)) に l2、(caddr (p f)) に l3 で (cadddr (p f)) が l4 という事で試験をしています。

frame の考え方の誤解

最初はこう考えていました。

(make-frame (make-vect 2.0 2.0)  ;; origin
	    (make-vect 4.0 2.0)  ;; edge1
	    (make-vect 2.0 4.0)) ;; edge2

_表示スクリーン上の点 (0, 0)_ からの、と思ってたら「フレームの頂点の原点からの変位を指定_とあった。
上記の実装で問題 2.49 の a を試験したらどでかいヒシ型が出てきて (とは言え、図形が描画された訳ではないのですが)、びっくり仰天。実装を見てもそうなるのは当たり前に読めてしまって困りました。きちんと文章を読みましょう、な典型です。(恥
でも、コード見て意味が類推できなかったあたり、微妙スギかも、と。(とほほ

ペインタに渡す線分に関する誤解

ペインタの実装を見るに、線分はどうやって指定するんだ、とアタマがこんがらがっていました。コード直下に「線分は単位方形に対する座標を使って与えられている。」とあり、やっぱりか、と。

ここまで分かればあとはざくざくヤレそう。ただし、描画の実装はカンニングが必要かも。(GLUTによる「手抜き」OpenGL入門??)