GuileのR6RS対応を試す

サマリ : 簡単なスクリプトなら動くが工夫が必要
Guile 2.0がそろそろリリースされる。このリリースの目玉は世間的にはJavaScript/EmacsLispのサポートな気がするが、ice-9が標準のモジュールシステムになったことで、Guileのモジュール構文がR6RS Schemeと互換になったことにも注目したい。
Guileは(GNU標準言語なので)一応世間的に知られたScheme処理系で、そのGuileと共通で使えるモジュールが書けるようになったのは、Schemeの相互運用性という点ではそれなりに前進するように思える。
しかし、現状ではGuileにR6RSライブラリを使わせるのはそれなりに工夫が必要になる。

  • .sls拡張子と.guile.sls拡張子に対応する

Guileは標準で.scmしか見にいかない。

(set! %load-extensions '(".guile.sls" ".sls" ".scm"))

のようなファイルを作って(guile-load.scmのような名前で保存し、)Guileの起動時に読ませる必要がある。
たとえば、racketのR6RS test suiteを走らせるには、

guile -l guile-load.scm -L racket/collects racket/collects/tests/r6rs/run/hashtables.sps 

のようなコマンドラインになる。
ちなみに、Guileはmoshと同じくpsyntaxをexpanderに採用している。よって、importのfor指定は無視され、expand時とrun時で同じ名前空間を共有できる。

コンパイルキャッシュの採用

Guile 2.0の重要な変化として、バイトコードVMを採用したことも挙げられる。このため、Guileはmoshやypsilonのようなバイトコードキャッシュを備えている。
バイトコードキャッシュは、基本的に~/.cache/guileに配置される。(nmoshも.cache以下にキャッシュを移す予定。このディレクトリはfreedesktop標準のキャッシュディレクトリであるため。)
Guileのバイトコードキャッシュも、(pure R6RSで実装された)includeのようにimplicitなファイル依存関係が生じたときは正常に動作しないように思える。

現状の互換性

低い。特に、portと例外を使ったスクリプトは動作しないことが多い。

test pass/fail
base error(exception handling)
bytevectors error(datum comment)
conditions error(record impl)
contrib error(exception handling)
control 11 pass
enums 26 pass
eval 3 pass
exceptions error(get-string-n)
hashtable 12/249 fail(exception handling)
io/ports error(expand?)
io/simple error(unimplemented: port)
lists error(exception handling)
mutable-pairs error?(timeout)
mutable-strings error(exception handling)
programs 2 pass
r5rs error(exception handling)
reader 70 pass
records/procedural 21 pass
records/syntactic 4/53 fail
sorting 4 pass
syntax-case error(exception handling)
unicode 22/118 fail

ただ、moshのbootstrapは現状のGaucheを使ったものから、時期を見てGuileを含めたR6RS Schemeへ移行するつもりなので、Guileとの互換性は今のうちからチェックしておこうと考えている。

R6RS-"compatible"という選択肢

Guileも"R6RSスクリプトを実行できるが要求されるチェックを全て実装しているわけではない"実装に分類される。同様の方針の実装には、Larcenyやnmoshも含まれる。
もっとも、R5RSでも同様の状況(こちらは処理系の裁量が大きい仕様)だったので、今後も既存の処理系がR6RSをサポートするときはGuileのようにライブラリ構文とAPIだけ可能な限り合わせるという方針になるように思える。