ochalog

RubyとMediaWikiとIRCが好き。

SICP:問題2.17

とても久しぶりにSICPの問題をやってみた。前回の問題から飛んでいるけど(一応間の問題も解いてはある)、今回初めて使ってみたGauche単体テストでの確認が便利だったので、思わず先に書いてしまった。

ochaochaocha3.hateblo.jp

問題 2.17

与えられた(空でない)リストの最後の要素だけからなるリストを返す手続き last-pair を定義せよ:

(last-pair (list 23 72 149 34))
(34)

計算機プログラムの構造と解釈 第二版 2.2.1 並びの表現」より

length と同じようにリスト全体の cdr ダウンで。Schemeの組み込みライブラリに同名の手続きが入っているので、my-last-pair という名前にした。

(define (my-last-pair items)
  (if (null? (cdr items))
    items
    (my-last-pair (cdr items))))

gauche.testを使ったテスト

ところで、今まではテストを手でやっていたのだけど、試すときに使っていたGauche単体テストのライブラリgauche.testが含まれていることを知り、今回初めて使ってみた。

上の手続きをex-2-17.scmというファイルに入れ、以下の内容のex-2-17-test.scmというファイルを作った。

;; 問題2.17のテスト

(use gauche.test)
(test-start "問題2.17")

(load "./ex-2-17.scm")

(test "要素数1の場合"
      (list 1)
      (lambda () (my-last-pair (list 1))))

(test "問題文の例"
      (list 34)
      (lambda () (my-last-pair (list 23 72 149 34))))

(test-end :exit-on-failure #t)

実行すると以下のように出力され、テストが成功したことが分かる。

$ gosh ex-2-17-test.scm
Testing 問題2.17 ...
test 要素数1の場合, expects (1) ==> ok
test 問題文の例, expects (34) ==> ok
passed.

テストが失敗するように、わざと以下のテストケースを入れるとどうなるか。

(test "絶対失敗する!"
      (list 23)
      (lambda () (my-last-pair (list 23 72 149 34))))

出力はこのようになり、失敗した場合の結果が分かりやすく表示された。

$ gosh ex-2-17-test.scm
Testing 問題2.17 ...
test 要素数1の場合, expects (1) ==> ok
test 問題文の例, expects (34) ==> ok
test 絶対失敗する!, expects (23) ==> ERROR: GOT (34)
failed.
discrepancies found.  Errors are:
test 絶対失敗する!: expects (23) => got (34)

かなり便利なので、今後答えがはっきりと決まる問題を解くときには、積極的に使っていきたい。