読者です 読者をやめる 読者になる 読者になる

テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

(msgpack-nim report) unwrapIntoの実装

とあるNim野郎がmsgpack-nimを使い出している. 彼の提案としては, 以下のようなコードが書けたらどうだろうかというのがある.

let x = st.unpack.unwrapInto(seq[tuple[a: int, b: string]])

これは, stream(st)からunpackした結果のMsgオブジェクトを, 任意の型のNimオブジェクトに変換するという操作だ. Haskell版などの実装ではきれいに実装されているが, Nimでは同じようにはいかない.

Nimでは, マクロを使う必要があると思う. 上のコードに対して, 動作の例を示すと,

  1. seqである. unwrapArrayを呼び出し, 各要素をさらにunwrapしよう.
  2. tuple[a:int, b:string]をunwrapする関数を生成して, 各要素をunwrapしていく.

擬似コードとしては以下のようになる.

st.unpack.unwrapArray.map {|x| f = makeUnwraper(tuple[a:int, b:string]); f(x)}

要点は, 型Tが与えれた時に, それを適切にunwrapする関数を作る(makeUnwrapper)ことである. 型でいうと, T -> (Msg -> T)となる. このような関数を, マクロを使って作ればいい.

ある型の情報を知るには, getTypeが利用出来ることがわかった. これを使うと, 与えられる型に制限を加えれば, たぶん実装出来る.

問題としては, 例えば, seq[tuple[key: K, val: V]]が二通りの意味(Mapである. tupleのseqである)を持ってしまい, フォーマットが異なることであるが, これはNimでは特殊にMapとして扱われているので, Mapとしてunwrapすればよいと思う. 他には, 仮にtuple[a, b: int]のように書かれた場合の対応である. 人間の目から見れば, これをtuple[a:int, b:int]と展開すれば良いように見えるが, 実際にこれをプログラムにやらせるのは簡単ではない. したがって, 必ずtuple[v0: t0, v1: t1, ..] の形を順守させることとして, もし違う場合はコンパイル時にエラーを出すという作戦で行こうと思う. macroはコンパイル時に評価されるので, 型が希望通りでないことはコンパイル時に判定出来る.

pycparserの経験があるので, ASTいじりに心的障壁はない. しかし, 幾分骨であると思うので, 地道に検討をして, いつか作れたらいいなと思っている.