言語処理系間でライブラリを共用する難しさ

comp.lang.schemeにも書いた https://groups.google.com/d/msg/comp.lang.scheme/GuHmoUNBplA/dykAeuE3CQAJ けど、処理系間でライブラリを共用するのはそれなりに難しい。
nmoshの次代ライブラリフレームワークであるyuniはこの問題に正面から取り組んでいる比較的珍しいプロジェクトで、独特のポジションに居るのではないかと思う。

Schemeと他の言語の違い

Scheme独占的な処理系が無いというのが非常に大きいポイントだと思う。実は世間で使われている言語の殆どには何らかのリーディング処理系が有り、そのような処理系に対応できないライブラリは単に存在しないのと同じと言い切って良い:

Schemeにはこのような処理系は存在せず、そもそもライブラリの共用を第一義としてデザインされたはずの標準であるR7RSやR6RSは現時点ではライブラリの共用にはあまり使えていない。
ただ、Schemeのように独占的な処理系を持たない言語が珍しいわけではなく、Common Lispのように機能しているデファクトスタンダード(asdf, quicklisp)を持つ言語もある。このため独占的な処理系の存在はライブラリの共用のために必須の存在では無いといえる。

yuniのフォーカス

たぶん全てのSchemeを名乗る処理系をサポートすることはできない。なのでyuniはサポートする処理系を限定することにした:

  • 現時点でメンテナンスされている(例えばChez移行後のRacketはサポートから落ちるだろう)
  • R6RSかR7RS smallのいずれかをサポートしており、かつ、FFIをサポートしている(C言語で書かれている場合)
  • R6RS/R7RS処理系の場合は、SRFI-6(string port、R7RSサポートに必要)、SRFI-30(S式の複数行コメント、無いと不便すぎる) が必須
  • syntax-rulesをサポートしていない処理系は自前のexpander(現状はAlexpander)でサポート

これだけ条件を絞っても適合する処理系は10程度は有り( https://github.com/okuoku/yuni/blob/127a7005ab1047ef16974dda75f12fcb95726295/README.md )、さらにcyclone( https://github.com/justinethier/cyclone )のように依然候補に上がる処理系は有る。
yuniはR6RSとR7RSを混ぜて使っている。ライブラリフォーマットはR6RS(R6RS-liteと呼んでいる)、標準ライブラリはR7RSという選択は、

  • R7RSライブラリ形式は現実のアプリケーションを開発するのには不向き & R6RSのlibrary構文はdefine-libraryの厳密なサブセットになっている
  • R7RSで追加された互換性構文(cond-expand)はChezのような処理系ではサポートされておらず無意味
  • R6RSの標準ライブラリはUnicode等実装が重いものを含んでいるため他の処理系にadoptされることはあまり期待できない
  • R7RSの標準ライブラリの殆どR6RSで実装できる

といった点に依る。
(String portやchar-ready?のようにR6RSでは実装のしようが無いものもあるが、String portはSRFI-6としてそれなりに普及しているので採用、char-ready?やu8-ready?は存在意義が無い http://d.hatena.ne.jp/mjt/20161020/p1 ため省略している)

リーディング処理系無しでライブラリエコシステムを作ることはできるのか?

仕様に無い挙動を規定してしまうような強い処理系はライブラリエコシステムの形成に良い影響を与える。というか、言語仕様だけで機能するライブラリエコシステムを作ることは非常に困難なのではないだろうか。。
yuniのモデルはリーディング処理系ではないものの、リーディングライブラリの位置を狙うことで同じことをしている -- char-ready?を切り捨てる選択をするには、どこかのタイミングで同じことをしなければならない。
個人的には、リーディング処理系にせよリーディングライブラリにせよ存在すること自体はそれほど悪いことでは無いと思っている。R6RSもR7RSもそれ単体ではライブラリエコシステムを作れないかもしれないが、その辺の経験を踏まえてR8RSなり必要なSRFIなりをデザインすれば良いわけで。。