今日の作業
mincamlのScala移植をとりあえず、コンパイル通さないで、
ひたすらシンタックスの書き換えのみに集中してやることにしました。おかげで、作業は捗りました。
見た目はScalaだけど、動かないプログラムソースが沢山出来ています。
githubにアップロードしたいところなのですが、設定がめんどいので後でやります。
Scalaって関数型言語だ!と言っているだけのことはあって、OCamlに備わっている機能のホトンドをカバーされているので移植は楽だと思います。これをJavaにとか言うともう、アセンブラで書けって言われてるくらい大変になるでしょう。
たとえば、assoc.mlをassoc.scalaに移植している途中のソースは以下のようになっています。
before OCaml
assoc.ml (* flatten let-bindings (just for prettier printing) *) open KNormal let rec f = function (* ネストしたletの簡約 *) | IfEq(x, y, e1, e2) -> IfEq(x, y, f e1, f e2) | IfLE(x, y, e1, e2) -> IfLE(x, y, f e1, f e2) | Let(xt, e1, e2) -> (* letの場合 *) let rec insert = function | Let(yt, e3, e4) -> Let(yt, e3, insert e4) | LetRec(fundefs, e) -> LetRec(fundefs, insert e) | LetTuple(yts, z, e) -> LetTuple(yts, z, insert e) | e -> Let(xt, e, f e2) in insert (f e1) | LetRec({ name = xt; args = yts; body = e1 }, e2) -> LetRec({ name = xt; args = yts; body = f e1 }, f e2) | LetTuple(xts, y, e) -> LetTuple(xts, y, f e) | e -> e
マッチングだらけです。如何にプログラミング言語の変換にマッチング構文が便利であるかが分かります。
プログラムも短くていい!けど、たまに書こうとすると書けない、忘れてる。グフっ。っとなります。
after Scala
// assoc.scala // flatten let-bindings (just for prettier printing) open KNormal // ネストしたletの簡約 (caml2html: assoc_f) def f(e) = e match { case IfEq(x, y, e1, e2) => IfEq(x, y, f e1, f e2) case IfLE(x, y, e1, e2) => IfLE(x, y, f e1, f e2) // letの場合 (caml2html: assoc_let) case Let(xt, e1, e2) => val insert = e1 => e1 match { case Let(yt, e3, e4) => Let(yt, e3, insert(e4)) case LetRec(fundefs, e) => LetRec(fundefs, insert(e)) case LetTuple(yts, z, e) => LetTuple(yts, z, insert(e)) case e => Let(xt, e, f(e2)) } insert(f(e1)) case LetRec(Fundef(xt,yts,e1), e2) => LetRec(Fundef(xt,yts,f(e1), f(e2)) case LetTuple(xts, y, e) => LetTuple(xts, y, f e) case e => e }
これをScalaに書き換えればこんなかんじ。型とか書いてないのでエラーになりますが気にしてはいけません。
これなら、しばらくScalaから離れていてもきっと読み返せばすぐに理解することができるでしょう。
その点がScalaに移植する理由の1つです。openは後でimportとかpackageとかで何とかします。