LunarMLの進捗2024

LunarMLの今年の進捗を振り返ります。この記事は言語実装 – Qiita Advent Calendar 2024の14日目の記事です。

昨年の振り返り記事と、今年のLunarML関連の記事は以下の通りです:

リリース

今年はバージョン0.2.0とバージョン0.2.1をリリースしました。

標準ライブラリーのIO周りを整備したこと、ドキュメントの整備、出力されるコードの短縮などが今年の改善点です。

「出力されるコードの短縮」は記事ではまだちゃんと紹介していないので、ここで紹介します。

出力コードの短縮

Standard MLや多くのプログラミング言語では、f (g x, h y) という風にネストした式を書けます。この形は必ずしも最適化には便利ではないので、LunarMLではCPS変換によって式をフラットな形にしています。つまり、途中の式も全て変数に割り当てています。このコード例なら

val tmp1 = g x
val tmp2 = h y
val tmp3 = (tmp1, tmp2) (* タプルの構築 *)
f tmp3

という感じです。

しかし、LunarMLの最終生成物はLuaやJavaScriptのコードであり、途中の式を全て変数に割り当てているとコードの膨張につながります。コードを出力する段階では、ある程度ネストした式になっていて欲しいです。

方針としては、「変数の使用が一回だけで、直後の文で使用されている場合に定義を展開する」という感じになります。

評価の順番には気をつけたいです。定義の展開によって評価の順番が入れ替わるとまずいので、現状のLunarMLはかなり保守的にやっています。

ターゲット言語によっては評価の順番が決まっています。確かJavaScriptは決まっていたと思います。一方、Luaは式の中の評価順は決まっていなかったと思います。というわけで、

val tmp1 = g x
val tmp2 = h y
val tmp3 = (tmp1, tmp2)
f tmp3

という中間コードがあったときにJavaScriptであれば

f([g(x), h(y)])

という式を出力することができますが、ターゲットがLuaの場合はせいぜい

local tmp1 = g x
f({tmp1, h(y)})

に変換するぐらいで、一時変数を完全に消去することはできません。

真面目にやるならグラフを作って依存関係と実行順を表現してなんやかんややることになると思いますが、現状のLunarMLはそこまで強力なアルゴリズムを実装していません。というか、関数呼び出しの展開もまだだったと思います(プリミティブ呼び出しのみ)。

この話題については、Luaへコンパイルする言語「Amulet」を作っていた人の記事があります:The Amulet backend | SquidDev

今後の方針

野望は色々あります。バックエンドを増やしたいというのは一つあります:

  • バイトコードバックエンドの実装(バイトコードの生成、VMの実装、REPLの実装)
  • ネイティブコードバックエンドの実装(C言語を吐き出すか、LLVMを使う)
  • WebAssemblyバックエンドの実装
  • PHPバックエンドの実装

生成したJavaScriptをWebで動かせるようにする、という目標もありました。

周辺環境の充実もさせていきたいです。例えば、パッケージマネージャーの実装です。

しかし、やりたいことを挙げていくとキリがなく、いくら時間があっても足りません。限りある時間で少しでも良いものを目指すには、何か確実に達成できる目標を立てたいです。LunarMLの今の「強み」はLuaを出力できることなので、Luaとの連携を充実させていきたいです。Luaとの連携の充実で、考えられるものを挙げます:

  • Luaの標準ライブラリーに対する型付きのバインディング
  • バインディング生成を効率化するコード生成ツールか何か
  • Luaのイテレーター(for文で使うやつ)をSMLからいい感じに使える仕組み

この先どれだけ時間を割けるか分かりませんが、開発は続けていくつもりなので、これからもLunarMLをよろしくお願いします。

GitHubはこちらです:https://github.com/minoki/LunarML

Spread the love