RandomThoughts

RandomThoughts

Folang

Contents:
  1. レポジトリ
  2. 開発動機
  3. 関連リンク
  4. 仕様検討
  5. 開発日記
    1. グローバル変数定義対応、Unionのgenerics対応 2025-03-02 (日)
    2. 2025-03-03 (月)
    3. 3要素タプルのサポート 2025-03-05 (水)
    4. UnionにStringerのメソッドを生成 2025-03-06 (木)
    5. match周辺の型リファクタリング、exhaustive checkを実装 2025-03-13 (木)
    6. stringのmatchを実装, letのinner関数定義を実装 2025-03-16 (日)
    7. csvplr移植、QFrameを評価 2025-03-19 (水)

FSharpっぽい見た目でGoとして動く言語を作りたいなぁ、と思い、Folangと名付けて開発をしている。

レポジトリ

karino2/folang: Funcitonal language transpiler to golang.

開発動機

dotnetはやっぱりかったるさがあるので、runtimeやデプロイはGoが良いと思う。 でも言語はFSharpみたいなのが好きなので、なんかトランスパイルでどうにかならんかな? 実用にはならなくてもgoのお遊びとして結構やってみたい気もする。

とりあえず簡単なシンボルのツリーからgoのソース生成するのを作って、それを発展させていってそれっぽいものに出来ないかしら? セルフホスト出来る感じに出来たらちまちま時間をかけて進めていけそうな気もするが。

fsharpを移植したいのではなく、ランタイム的にはなるべくgoそのままにしたい。プラスアルファで型情報くらいは追加で持ってもいいかもしれないが。 という事で言語的には全く新しい言語になるだろう。

関連リンク

参考になりそうなリンクを貼っておく。

golang関連

golangによる言語処理系

参考になりそうな関数型言語系

その他

仕様検討

開発日記

やった事を書く場所が欲しくてとりあえずここに置いておく。

Folang過去ログ

グローバル変数定義対応、Unionのgenerics対応 2025-03-02 (日)

Unionのgenericsを対応するにあたり、再帰型の扱いが難しくなってきて、lookupを必要になるまで遅らせるように直したくなる。 けれどいちいちlookupの辞書を全てに渡すのは嫌(大変更だから)なので、グローバル変数に対応しよう、と思い立つ。 これまでもGoの側で定義して関数でラップすれば使えたけれど、 別にグローバル変数に対応しても良いでしょう。

Golangのグローバル変数は、右辺が定数じゃないとconstは使えないので、全部varにする。

グローバル変数を使ってレコードやUnionの情報を辞書に入れて必要になるまでlookupを遅らせることでrecurive問題を解決し、 それをベースにUnionのgenerics対応をする。 なんとなく動いている風味か?

2025-03-03 (月)

今後のタスクを考えたい。とりあえずcsvplrを移植したいなぁ、と思っているので、 パーサーコンビネータを作りたいと思っている。簡単な奴。 そのためにUnionのgenericsを実装したみたいな所もある。

そのためにも必要なことを列挙してく

  • package_infoにUnionを書けるようにしたい
  • openが欲しい
  • ビルドイン型を作りたい(frtに定義)

この3つくらいかな。ビルドイン型はResult、Option、Dictあたりはビルドイン型にしたい。frtの型をプレフィクス無しで見えるようにするだけでいいとは思うんだが。

一方で今書いていて思ったが、パーサーコンビネータを作るだけなら上2つだけでいいな。もっと言えば一番上だけで良い。 ただparserはプレフィクスとしては長いので、そろそろopenは欲しいかもしれない。

とcsvplrのコードを見直してみたが、意外と面倒な機能をいろいろ使っているな。 次のターゲットにはあまり良くないかもしれない。 むしろ相互再帰のあるパーサーはparsecでは変数の副作用を使っているので、こういうのはgolangで書く方がいいのでは、という気もしてくる。

むしろ現状のセルフホストのパーサーをgenericなUnion使う版に書き直すか?もともとside effectがあまり無いスタイルのパーサーなので、 コンビネーター的なものになりつつあるので、もっと推し進めてもいいかもしれない。

一方でせっかくだから、いろいろな用途に使っていきたい、という問題もあるな。 csvplrは思ったより大変なのでもっと簡単な用途がいいかもしれん。

3要素タプルのサポート 2025-03-05 (水)

確定申告の息抜きにパーサーのコードを見直したり整理したりしていた。

ifとelifを並べたコードは、生成したコードが美しくないので、 matchのstringが欲しいなぁ、という気がする。 ただfolangとしては別にelifが並んでいるのはそんなに悪くないので、優先度は微妙。 実装もそんなに大変ではないはずだが。

あと、パーサーを、もっと共通で使える道具を増やしていこうとすると、以下のようなネストしたdestructuringに対応したいなぁ。

let (a, (b, c)) = ...

これがあれば、値を返すパースを2つつなげてtupleにする、という関数を作れば、 パーサーをつなげて書ける所が多い。

現状は、以下のコードは

let (a, b) = rhs

以下にトランスパイルされているが、

a, b := frt.Destr(rhs)

これが二段階になればいいのか?

a, _t0 := frt.Destr(rhs)
b, c := frt.Destr(_t0)

二行目以降の右辺は単なる変数になるのだから、再帰的にやっていけばそんなに大変ではなさそうではあるが。

csvplrが3要素タプルを使っていたのでサポートした そうしたら、これまで決めていた以下のルール、

  • []T*U[](T*U)
  • T*[]U もvalid

の延長で、T*U*VT*(U*V)になってしまって2要素タプルとみなされるように。 これは駄目だ。

やはり []T*U([]T)*U とパースするしかないかぁ。

alecthomas/participle: A parser library for Go のexamplesのexpr4を見ていたら、手書きパーサーの例が出ている。 おぉ、いいじゃん、こういうのやりたかったんだよ、ということでparticipleでcsvplrの移植をやってみることにする。

UnionにStringerのメソッドを生成 2025-03-06 (木)

デバッグ時に不便なので、Stringerを生成することにした。とりあえずUnionだけ。 Recordもそのうちやってもいいかもしれないが。

csvplrのパーサーをparticipleで書いてIRはUnionを生成するのができた。まぁまぁ簡単に出来たな。このくらいならF# とそんなに面倒さは変わらない気がする。 次はdataframe系のパッケージを使ってcsvのやりとりか。

csvplrの移植はなかなかいい感じのタスクな気がしてきた。

文字列のマッチとinner関数のletはそろそろ対応してもいいかもな。 後者は内部的にはfunのletに変換する感じにして単なるシンタックスシュガーとして扱う感じで。

match周辺の型リファクタリング、exhaustive checkを実装 2025-03-13 (木)

stringのmatchをそろそろサポートしたい、と少しやってみたが、どうも既存のmatchのcasesの型がよろしくなく、 一緒に変更したらなんかいつまで経ってもコンパイル出来ない感じになってきたので一旦stashして型のリファクタリングから。 いい感じになる。

stringのパターンを増やすといかにも追加し忘れが出てきそうなので、exhausitve checkを実装することに。 割とあっさり実装出来て、これまで漏れてたのも見つかっていい感じ。

stringのmatchを実装, letのinner関数定義を実装 2025-03-16 (日)

地味に変更が多くてやる気が出なかったstringのmatchをようやく実装。 その過程でトランスパイルのエラーメッセージを改善。だいぶエラーの場所をちゃんと教えてくれるようになってきた。

ついでにletのinner関数定義を対応。内部的には以下を

let localf a = someExpr

以下に変換している。

let localf = fun a -> someExpr

ちなみにこのaは、親の関数のtype parameterとして解釈されるため、このlocalfはこの関数内では一つの型としてしか使えない。(親の関数を呼ぶ時にお異なるtype argを与えて別の型にする事は出来る)。

これでcsvplrを移植するのに必要な機能は揃ったかな。

最近の変更分のドキュメントを更新しておく。まぁ読んでる人がどれだけいるかは微妙だが。

csvplr移植、QFrameを評価 2025-03-19 (水)

Folangの応用としてcsvplrを移植するのに、DataFrameのライブラリを選び、QFrameを使ってみる事にする。

tobgu/qframe: Immutable data frame for Go

この辺は特にこだわりは無いので使ってみて駄目ならほかを試す感じで。

見た感じ結構高機能なので、csvplrを移植するよりも、ASTから直接このQFrameのフィルタとかを生成する方がいいかもなぁ。