週刊mosh - R7RS導入開始 / 非同期処理構文

年内には0.2.8を出したいところだが。。
今のところ入りそうなのは、

  • 非同期I/O API(nmoshのみ)
  • R7RS smallの各種ライブラリサポート(nmoshのみ)
    • cond-expandやevalなど一部機能は無し
    • 構文等も。
  • Cursesのサポート(nmoshのみ)
  • MessagePackサポート

いくつかの機能は諸般の事情でdrop。Bootstrapのサポートも無しかな。。
MessagePack/RPCはサポートするかも。

R7RS導入開始

R7RS bridgeを統合してnmoshから(scheme base)のような各種ライブラリが使えるようになりました。
一部まだ未実装な点があって、mapやassocがSRFI-1じゃないとか、vectorがself-quoteでないなどリーダ構文の差異等も有。
SRFI-46なsyntax-rulesは実装されているので、macroを生成するmacroが微妙に簡単に書けます。
caseの拡張(cond風の => 構文)も実装したけど、いまいちこれの便利なシチュエーションが思いつかない。。condと違って、caseにマッチした値って絶対にcaseの引数だよね。。

非同期処理構文(yuni async)

nmoshにはNode.jsのようなコールバック方式の非同期I/O APIが乗りますが、プログラムが超ネストする問題があるのでネストしなくなる補助構文(seq構文)を用意しました。

(output target bv len
        (^[res]
          (output target bv-next len-next
                  (^[res] 'ok))))

こういうcallbackの連鎖が、

(seq
  (=> output target bv len => res)
  (=> output target bv-next len-next => res))

こういうふうに書けます。defineのように変数スコープを式の順序で決めてしまうので使う際は要注意。

  • フェーズID、エラーチェックとハンドラ

seq構文によって投入されるジョブにはIDを振ることができます。IDはエラーハンドラを記述したときにエラーハンドラに渡されます。

(seq
  ;; Error Handler
  => (^[id . x] (format #t "ERROR! ~a ~a\n" id x))

  (=> '"Phase1" output target bv len => (res))
  (format #t "res = ~a\n" res)
  (=> '"Phase2" output target bv-next len-next => (res))
  (format #t "res = ~a\n" res))

seqの直後に=>を書くとその次の式がエラーハンドラとみなされます。seq中のジョブの先頭に(quote xxx)のように書くことでジョブのidを設定して、エラーが起きたときにエラーハンドラに渡せます。
callbackのreceiverをlistにするとその値が真かどうかがチェックされ、真でなければエラーハンドラが起動されて以降の式は実行されなくなります。
...この手のことは継続を使えば特殊な構文を使わなくても出来るんですが、moshはあまり継続のキャプチャが高速でないようなのでなるべく継続を使わない方向で。。