EoPL reading (106) 2.3 Representation Strategies for Data Types

OSC の合間をぬって練習問題をナニ。電気が無いので紙の上で検討してたりして。
ごにょごにょしてて以下がでっち上がりました。

(add-load-path ".")
(load "Fig2.3")

(define n-cdr
  (lambda (n l)
    (if (= 0 n)
	ls
	(n-cdr (- n 1) (cdr l)))))

(define list-find-last-position
  (lambda (n sym los)
    (cond ((null? los) n)
	  (else
	   (let ((pos (list-index (lambda (sym1) (eqv? sym1 sym)) los)))
	     (if pos
		 (list-find-last-position (+ n pos)
					  sym
					  (n-cdr pos los))
		 n))))))

あまり自信は無いです。とりあえず n-cdr な試験から。

(test-section "n-cdr")
(test* "n is 0"
       '(a b c)
       (n-cdr 0 '(a b c)))

n が 0 ならそのまま戻す。

(test* "(n-cdr 1 '(a b c)) return '(b c)"
       '(b c)
       (n-cdr 1 '(a b c)))
(test* "(n-cdr 2 '(a b c)) return '(c)"
       '(c)
       (n-cdr 2 '(a b c)))
(test* "(n-cdr 3 '(a b c)) return '()"
       '()
       (n-cdr 3 '(a b c)))

これ、n と (length l) のナニは略で良いのかどうなのか。こんなモノとして本体の試験に着手。
って、これ存在しない場合、0 が戻るんですがどうしたものやら。pos が偽で n が 0 なら偽を戻すか。

	   (let ((pos (list-index (lambda (sym1) (eqv? sym1 sym)) los)))
	     (if pos
		 (list-find-last-position (+ n pos)
					  sym
					  (n-cdr pos los))
		 (if (= 0 n)
		     #f
		     n)))))))

で、見つからないケイスの試験が以下。

(test-section "list-find-last-position")
(test* "(list-find-last-pos 0 'z '(a b c)) -- not found"
       #f
       (list-find-last-position 0 'z '(a b c)))

試験失敗。よく見たら list-find-position でなくて list-index 使ってますな。修正。

(define list-find-last-position
  (lambda (n sym los)
    (cond ((null? los) n)
	  (else
	   (let ((pos (list-find-position sym los)))
	     (if pos
		 (list-find-last-position (+ n pos)
					  sym
					  (n-cdr pos los))
		 (if (= 0 n)
		     #f
		     n)))))))

で、再試したらパスとの事。試験追加。

(test* "(list-find-last-pos 0 'a '(a b c)) returns 0"
       0
       (list-find-last-position 0 'a '(a b c)))

で、試験起動したらループした。プラいちしないとダメな事に気づく。ってか上記実装は全然ダメって事な模様。どうしたものやら。
で、時間けっこうギリですが以下がでっち上がる。

(define list-find-last-position
  (lambda (n sym los)
    (let ((pos (list-find-position sym los)))
      (if (not pos)
	  pos
	  (let f ((n (+ n pos)) (sym sym) (los (n-cdr (+ pos 1) los)))
	    (let ((pos (list-find-position sym los)))
	      (if pos
		  (f (+ n pos) sym (n-cdr (+ pos 1) los))
		  n)))))))

なんかごちゃごちゃしてるなぁ。上記の試験にはパスしている模様。でテキストにある以下の例を試してみたんですが

(test* "(list-find-last-pos 0 'a '(c a b a c a d e)) returns 5"
       5
       (list-find-last-position 0 'a '(c a b a c a d e)))

3 が戻る、と叱られる。

test (list-find-last-pos 0 'a '(c a b a c a d e)) returns 5: expects 5 => got 3

とほほ。原因は分かったんですがどうすりゃいいんでしょ。無理矢理ですがこうか。

			 (f (+ n (+ pos 1)) sym (n-cdr (+ pos 1) los))

結局 pos に 1 加えた値をナニしないと駄目なのか。とほほ。
一応以下な試験も追加。

(test* "(list-find-last-pos 0 'a '(c a b a c a d a)) returns 7"
       7
       (list-find-last-position 0 'a '(c a b a c a d a)))

パスしてます。一応できた、ってコトで良いのかどうか。