Scrap your boilerplate

by syoyo

Scrap your boilerplate
http://www.cs.vu.nl/boilerplate/

“Scrap your boilerplate” と呼ばれる、Haskell 向けのジェネリックプログラミングライブラリを知りました. Haskell におけるデザインパターンとも言えるでしょうか.

Haskell で RSL(RenderMan Shading Language) コンパイラを書いていると、AST(抽象構文木) などのツリー構造なデータ型の一部にだけ作用させたいコードが必要なときがよくあるのですが、この scrap your boilerplate がまさにそれを解決してくれることが分かりました.

たとえば、以下ような例を考えます.

replaceConst 関数は Expr の Const ノードを Var ノードに置き換えます.

Expr や Stmt は Main クラスに属しています.
Main クラスのインスタンスにたいして replaceConst 関数を作用させるためには, Expr, Stmt の両方にたいして replaceConst を実装する必要があります.
しかし、Stmt のほうは、実際には Expr を見つけて”トラバースするだけ”の画一的でつまらないコードです. つまり、Stmt に対する replaceConst は、本質的には必要ないものなのです.

Boilerplate とは、ボイラー版という意味もありますが、辞書を調べると「画一的なもの」「共通事項」という意味もあります.
“Scrap your boilerplate(SYB)”とは、Stmt に対する replaceConst の実装コードに見られるような、画一的で共通なコーディングをなくそう!というような意味のようです.

Data.Generics

SYB では Data.Generics というものが提供され、データ型の deriving に Typeable, Data を付加すれば、無駄なコーディングを省き必要な部分のコードを書くだけでよくなるという、なんとも素晴らしい機構です.
(もちろん、SYB の論文を見るとそれ以上にいろいろできる仕組みのようです)

SYB で書き換えると、こんな感じでとてもすっきりします.

まず、SYB(Data.Generics) を使うには、コンパイラに、拡張として DeriveDataTypeable を指定する必要があります.

そして、Data.Generics を使うことで、Stmt に対する replaceConst のコード、つまり “boilerplate” なコードを記述する必要が無くなっています.

boilerplate な処理であるトラバースのコードは

everywhere (mkT a) b

で代用されます. これは、a を、b のそれぞれのコンストラクタに対してトラバースして適用する、ということをしてくれるようです(a, b はどちらも Typeable, Data を derive しているとする).

まとめ

RSL コンパイラを書く上で、AST に対してなにか処理をさせたいときに、AST を構成するデータ型それぞれにたいしてトラバースするコード(boilerplate なコード)を書かなければならないのはなんとかならないものかと思っていたので、SYB はちょうどよい発見でした.
が、こんな良い手法(デザインパターン)があるのであれば、願わくば RSL コンパイラを書き始める前に知っておきたかったですね.

うーむ、Simon P. Jones(偉大なる Haskell 野郎) の文献をまずは一通り眺めたほうがいいのかも.

https://research.microsoft.com/en-us/um/people/simonpj/papers/papers.html

… と思ったけど、これはちょっと文献多すぎですぐには読みこなせないですね…
一日 3 本くらいをノルマとして読んだとしても、1, 2 ヶ月はかかりそうだ.

Advertisements