R7RS smallをSDK用にサブセットする

yuniは基本的にR7RSを基盤としている。が、ゲームエンジンなりなんなりを書いていく上で互換性の維持が難しかったり、マイナーであったりする機能は削って移植性を確保したい。他のScheme共通ライブラリ、例えばslibはもっと心が広い( http://srfi.schemers.org/srfi-96/srfi-96.html )が、yuniは高度なライブラリはFFIに委ねるデザインなのでずっと狭い心でも問題無いと期待できる。
基本的には互換層の維持コストを下げることに注力することが求められている。個人的には互換層の設計/実装は割と本業だけど、現状のyuniの規模がそろそろ限界のように思える。
yuniのライブラリがSchemeで標準的に存在すると期待する機能を使用する場合は(yuni scheme)ライブラリを使用する。(yuni scheme)ライブラリは、同名のR7RS small手続き/構文とほぼ同じ機能性を(R6RS上でも)提供する。
元々、yuniでは(scheme base)等R7RS smallのライブラリを直接使用しようと考えていたが、Racketには互換性の無いscheme/baseライブラリやscheme/fileライブラリが既に存在し、3rd partyのR7RS実装はRacket標準のR6RSと互換性が無いため、基本的にR7RS smallを共通層として提供するアイデアは捨てている。(Racket以外のR6RSでは既存のコードの移植用にR7RS smallも提供する)

ハイレベルな判断基準

いくつかのハイレベルな基準を設けている:

  1. メジャーな処理系に実装されていない機能は省略する。get-environment-variables(Chezに無い)。
  2. 実装が面倒で滅多に使われない機能は省略する。ratnum。
  3. OS/カーネル間で互換の取れない機能は省略する。char-ready?とu8-ready?。
  4. 処理系間で互換のとりづらい機能は省略する。cond-expand。
  5. R7RS smallの補助構文およびそれを消費する構文は省略しない。=> とか _ 。

補助構文を省略しないのは、Yuniでは補助構文の使用は基本的にR7RS smallで提供しているものだけを許可しているため。例外は代入を表わす終端子 := で、これは歴史的事情で残ってしまっている。(yuni core)ライブラリでは、C言語で言うところの、

theStruct.field.entry = 10;

(~ theStruct 'field 'entry := 10)

と書けるような構文をかなり昔から提供してしまっており、今更変えられない。この := は補助構文だがR7RSに無い。

(yuni scheme)の中身と省略した標準ライブラリ

基本的にはR5RS - αになるように調整している。

ここに入っていないライブラリはyuniでは要求しない。Yuniのアプリケーションが使う可能性は有るが、yuniの提供するFFIレイヤのような機能は、(yuni scheme)の範囲で記述する必要がある。

  • (scheme eval)(scheme repl)の扱いは未だ決めていない。特にreplはR6RSに無いので処理系毎に互換レイヤを作る必要があるが、提供する価値は有る気がしている。GambitやMIT/GNU Scheme上ではYuniはexpanderも提供しなければならず、expanderは巨大なので別ライブラリに分けておきたいため(yuni scheme)には入れないつもり。
  • (scheme load)はyuniが提供する予定のprecompileと相性が悪い(yuni側のLoad機能を使用させる必要があり、R7RSのloadとセマンティクスが合わない可能性が高い)ため提供しない。
  • (scheme char)ロケールに依存するためyuniでは扱わない。7bit ASCIIとUnicodeは専用のAPIを別途提供しても良いかもしれない。文字コード独立性を言語的に提供すべきかどうかは議論の有るところだが、少くともyuniでは文字コード独立の手続きにユースケースが無い。
  • (scheme complex)は有ると便利かもしれない。。これはratnumにも同様の事が言え、有れば便利かもしれないけど直近でユースケースが無いので省略。
  • (scheme time)は提供するかどうかは悩み中。FFIでOSのインターフェースを直接利用すれば良いのでこれといった要求は無いが、大抵のR7RSは提供しているようなので有っても良いかもしれない。
  • (scheme r5rs)は特に要求が無い。

省略したbase機能

いくつかの基本的語彙は省略している。
ratnum関連の手続き(rational?、rationalize、denominator、numerator)は特にユースケースが無いので省略。numeric towerの不完全な処理系にyuniを移植することを考えると、数値演算はinexactくらいを取り込むのが限度のように思える。現実的には、inexactの無い処理系は無いと考えて良いはず。
char-ready?とu8-ready?は仮に実装されていたとしてもポーリングしかできないため全く役に立たない。char-ready?をタイムアウトの無いselect(2)で実装した場合はfd→portが安全に実装できなくなる - 他所のスレッドやプロセスにデータを吸われるとデータはreadyでなくなる - ので、この手続きの機能を保ったままportを共有可能にするのは難しい。
include、importはライブラリの構文なのでプログラム中で使わせることは望ましくない(完全にexpandしないと依存ライブラリが導出できなくなる)。暗黙のバイトコードコンパイルキャッシュを持つ処理系では、処理系がincludeを提供していない限り正確に実装できない。
cond-expand、featuresは処理系によって対応がまちまちなので役に立つシチュエーションが思いつかない。また、R7RSのcond-expandはライブラリの存在をクエリ可能なため、ライブラリのインストールにより暗黙に挙動の変わるライブラリが実現できてしまう。そんなのデバッグできるか!
get-environment-variablesはChezに無い。環境変数へのアクセス自体は、コマンドラインユーティリティを書くのに便利なので有っても良い気はするが、列挙はあまり必要性が感じられない。
こうして書いてみると、lazyも要らない気がするな。。

存在するけど縮小する機能

call/cc。Full continuationは個人的には悪くないと思ってるけど、Kawaの制約に合わせる。Kawaのcall/ccは、継続を脱出方向にだけ使用でき、継続から返るのは高々1回に制限される。https://www.gnu.org/software/kawa/internals/complications.html
yuniはFFIと共に使用されるのが前提のライブラリセットになるわけで、副作用有りまくりのFFI呼び出しと、継続が組み合わさったプログラムをデバッグするのはちょっと考えたくない。。