拡張構文
moshを改造する前に小規模な実装で試してみることにした。mosh付属のパーサを改造するのが地味に難航しているので。
キーワード
Gauche由来のキーワード記法。一種のリーダーマクロ。
:hoge => (keyword hoge)
myuniには(並列プログラムの効率性のために)分離された名前空間を持たせることにした(※)ので、この手の"字面上の"シンボルを表現するための記法が必要になる。キーワードは特別扱いされ、特に宣言しなくてもプロトコルを生成する。
後置の:はSRFI-88のために予約することにした。
これはSRFI-42と衝突するが、SRFI-42の実装は専用のものを用意する予定。また、:で始まるシンボルを通常の目的で使うことはほぼ無いと考えられるので特にエスケープの類は用意していない。Guileのように切り替え可能としている実装もある。
(GaucheやCLのキーワードと違って、動的にキーワードを生成することは出来ない。要するにstring->keywordのようなものは今のところ提供されない。)
※ : 要するに他所のプロセスからreceiveしたデータはシンボルが含まれていてもinternされず、同じ名前のシンボルでもeq?が成立しなくなる。しかし、keywordに関しては、RPCにおけるIDLのように働き、リモートに対して送受信してもeq?は成立し続ける。
ユニフォームベクタ
#u8(1 2 3 4) ; R6RSはvu8を使うことに注意。 #f16(1.2 3.4)
SRFI-58(Array)は必要な機能が無いので不採用。moshにはユニフォームベクタは無いので今のところ対応出来ない。スクリプト中での表記はクリッピングを表現することは出来ない。固定小数点のQ-formatに対応すべきかもしれない。
vu8は外部表現やパケットの表現のために利用され、u8は内部データの値域限定のために利用されるという違いがある。実際にはvu8とu8は同様の目的に利用できるが、書き分けの余地を残している。
短いlambda
(^ (x) (+ x x))
これは統一性のために導入されている。多分普通のスクリプトではlambdaと記述されるべきだろう。実際には構文ではないリードマクロ。
(コロンと異なり、)R6RSはinitialとして^を許可している。 追記: special-initialに両方有った(R6RS 4.2.1)。
拡張文字列構文
- 文字列の補完(String interpolation)
(let1 hoge "fuga" #$",hoge fuga") => "fugafuga"
Gaucheにも同様の機能をもつ構文が有るが、R6RSのquasisyntaxとの競合を避けるために変更された。Substitute。
1つの空白文字またはピリオドをセパレータとして利用できる点が異なる。空白とピリオドは今のところ単純に消去されるが、TeX風に、空白は空白のまま出力するようにするかもしれない。|によるエスケープは検討中。
歴史的には、僕の処理系はよく[ ]をエスケープに使っていた。これは正規表現や通常のカッコと紛らわしいが、Shiftを押さずに入力でき*1、視覚的にわかりやすいというメリットがある。
(let1 hoge "fuga" #$"[hoge]fuga") => "fugafuga"
こちらに戻すかも知れない(,を利用した表記は、もともとquasiquoteからの連想に依るため)。しかし、[]と()を等価にするR6RSのルールには反するという問題がある。つまり、上の例でhogeを手続きとして評価するには以下のように書かなければならず、([hoge])のように書くことは出来ない。
(let1 hoge (^ () "fuga") #$"[[hoge]]fuga") => "fugafuga" (let1 hoge (^ () "fuga") #$"[(hoge)]fuga") => "fugafuga"
また、make風の$()表記も検討すべきかも知れない。
- Verbatim string
#vu8"HOGE" #u8"HOGE" ; 同上 #$vu8",HOGE fuga"
文字列ではなく、ASCIIの印字可能文字または\nなどのよく利用されるエスケープを利用したユニフォームベクタを生成する。漢字等のいわゆる8bit文字の扱いは未定。
名前は、ソースコードの表現そのままをユニフォームベクタにすることから。bytestring?
補完も同様に利用できるが、多くの人が期待するような動作では無いだろう(単に通常の文字列補間を行い、結果のASCII表記をユニフォームベクタにして返す)。また、この構文に対して補間が使えてしまうのは対称性を損なうかも知れない。つまり、以下のような記述も期待できるが、実際には意味がない(普通にシンボルを書けば良い)。
#$(1 2 3 4) ; substituted vector?
- 文字列/ベクタ構築手続き
#^"HOGE<>" ; cut-ish string #^vu8"HOGE<PACK-SPEC>" ; 型の指定
String interpolationよりも応用範囲が広いが、コンパイラがこれを理解するわけではないので非効率なコードを書きやすいかも知れない。TLVを表現するために、正規表現風のキャプチャを追加したいが、今のところうまい表記が無いので保留。
SRFI-8風の構文でscanf相当のことができると良いかも知れない。しかし、構文が複雑になるので何らかのトリックが必要だろう。
この構文も対称性を損なう問題がある。以下のような記述はlistではなくvectorを返してしまうだろう。
#^(a b c <> d) ; cut-ish vector?
実際にはこのような構文は無いのでエラーになる。
構文的には、通常の文字列に加えて、receiving-stringとsubstituting-stringを追加している。前者は順序づけされた複数の引数を取り、>等をエスケープする必要がある。後者はシンボルを含むことが出来、,等をエスケープすることになる。
*1:Shiftの習慣を普段の文字入力から変える必要がない