既存ライブラリのR6RSへの移植

SLIBのformat(version 3.1)を移植しました。6行コメントアウト、7行追加、後は(library ...)で包んだだけでした。以前はSLIBがインストールされていないと面倒だったような覚えがあるんですが・・・わたしの勘違いだったのでしょうか(汗

Ypsilon 0.9.6-trunk/r286 Copyright (c) 2008 Y.Fujita, LittleWing Company Limited.
> (import (slib format))
> (format #t "~,,'.,4:d" 100000000)
1.0000.0000
> (format #t "~,4f" (sqrt 2.0)) 
1.4142
> (format #t "~{~a~^, ~}" '(1 2 3 (a b (c d)) 4 5))
1, 2, 3, (a b (c d)), 4, 5

SLIBの説明によると、”An almost complete implementation of Common LISP format description according to the CL reference book Common LISP from Guy L. Steele, Digital Press. Backward compatible to most of the available Scheme format implementations.”とのことです。

SRFIの方は13, 14, 19, 27を追加して。以下のようになりました。

  • SRFI 1: List Library
  • SRFI 6: Basic String Ports
  • SRFI 8: receive: Binding to multiple values
  • SRFI 13: String Library
  • SRFI 14: Character-Set Library
  • SRFI 19: Time Data Types and Procedures
  • SRFI 26: Notation for Specializing Parameters without Currying
  • SRFI 27: Sources of Random Bits
  • SRFI 28: Basic Format Strings
  • SRFI 38: External Representation for Data With Shared Structure
  • SRFI 39: Parameter objects
  • SRFI 41: Streams
  • SRFI 42: Eager Comprehensions
  • SRFI 98: An interface to access environment variables

SRFI逆引きSchemeで見かけたものから移植しています :)

初めて見るコードをいきなり移植しているわけなのですが、未定義識別子の存在が許されないR6RSライブラリの仕様のおかげで作業が早いです。
例えばSLIBのformat.scmの場合、emacsなりでformat.scmを読み込んで全体を次のように囲みます(私の場合はeclipseで)

(library (slib format)
  (export format)
  (import (rnrs))
  ;;; "format.scm" Common LISP text output formatter for SLIB
  ; Written 1992-1994 by Dirk Lutzebaeck (lutzeb@cs.tu-berlin.de)
  ; 2004 Aubrey Jaffer: made reentrant; call slib:error for errors.
       :
       :
  )

そして、これを全部まとめて評価。

error: attempt to reference unbound identifier provided?
  >  (provided? 'inexact)
  ..."/dev/stdin" line 46

とかエラーが出たら(このエラーは実行時ではなくマクロ展開時に報告されます。ですので通常は通らない実行パス上に未定義識別子がある場合でも見逃すことがありません。これはCプログラムで未定義シンボルがリンクエラーになるのに似ています)

バッファの46行目をみてどう使われてるのかを確認・・・

  (define format:floats (provided? 'inexact))
  ;; Detects if the scheme system implements flonums (see at eof).

他にprovided?を使っている場所も見て対応を考え、ファイルの最初に

  (define provided? (lambda (x) #t))

を追加して再び全部まとめて評価。そして未定義エラーが出たらならば、同等の機能をもつR6RSの手続きで定義したり、(rnrs r5rs)を(import ...)に追加したり、という作業を繰り返します。
そうしていると・・・

(library (slib format)
  (export format)
  (import (rnrs)
          (rnrs r5rs)
          (rnrs mutable-strings)
          (rnrs mutable-pairs)
          (only (core) pretty-print))
  (define string-capitalize string-titlecase)
  (define force-output flush-output-port)
  (define call-with-output-string call-with-string-output-port)
  (define slib:error assertion-violation)
  (define slib:tab #\tab)
  (define slib:form-feed #\page)
  (define provided? (lambda (x) #t))
  ;;; "format.scm" Common LISP text output formatter for SLIB
  ; Written 1992-1994 by Dirk Lutzebaeck (lutzeb@cs.tu-berlin.de)
  ; 2004 Aubrey Jaffer: made reentrant; call slib:error for errors.
       :
       :
  )

ファイルの最初の部分がこうなったところでエラーが出なくなり、それと同時にformatも動くようになっていました :)
次にファイルの最後にこんな風に書き足して。

  ) ; <- ライブラリフォームの最後のカッコ
(import (slib format))
(format #t "~,4f" (sqrt 2.0)) 
(format #t "~{~a~^, ~}" '(1 2 3 (a b (c d)) 4 5))
       :
       :

ライブラリフォームの最後のカッコとimportの最後のカッコとテストコードの最後のカッコを順番に評価して動作を確認します。この時にバッファをセーブしたりライブラリのディレクトリにformat.scmを配置したりする必要が無い所がインタープリタの良いところです :^)
上手く動いているならライブラリフォームの下に書いたテスト用のコードをテストスクリプトに移してformat.scmをライブラリ本体だけにします。そしてセーブしたファイルをライブラリのディレクトリに配置してもう一度チェックを行います。

未定義の識別子が存在するだけでエラーとなって読み込むことすらできないというR6RSライブラリの仕様は不自由なのではないかと思っていましたが・・・これはこれでなかなか良いものですね :D