Arantium Maestum

プログラミング、囲碁、読書の話題

非S式なRacket後継言語?のRhombusとShrubbery記法について

個人的に作りたい自作言語の構想というのは結構昔からあって、ありていに言ってしまえば「Pythonチックなインデントベースでスッキリした構文でモジュールまで含めたMLの意味論を持つ言語」となる。

ただしMLのような式ベースの言語が破綻しない構文というのは少し考えどころで、年単位で寝かせていたのだけど(ML言語を実装する実力がなかったというのもある・・・)。

最近Shrubberyという記法に関する資料を目にして、これをある程度転用できないかと考えている。

Shrubberyは出てきた経緯も含めてなかなか面白いので紹介してみたい。

コトの発端

2019年7月14日、RacketConにてRacket界に激震が走った。

RacketコアチームのMatthew Flattが発表中に「次のバージョンのRacketはS式じゃない構文にしたほうがいいんじゃないかと考えている」と発言したのだ。

その日彼がRacket mailing listに送ったメッセージはこう始まっている:

Matthew Flatt 2019/07/14 19:30:04 To: Racket Users tl;dr DON'T PANIC

At RacketCon today, after summarizing the state of work on Racket CS, I recommended that we next explore the possibly of changing to an infix-oriented syntax in "Racket2".

You can find the recording here:

https://www.youtube.com/watch?v=dnz6y5U0tFs

そのRacketConでの発言を書き起こして補足したメールを読むと

Partly, I believe that a syntax with infix operators, fewer parentheses, etc., would be better. That's a matter of opinion, but at least it's an opinion backed by enough experience with parentheses that it can't be written off as uninformed. More significantly, parentheses are certainly an obstacle for some potential users of Racket. Given the fact of that obstacle, it's my opinion that we should try to remove or reduce the obstacle.

そして

I have in mind "Honu: Syntactic Extension for Algebraic Notation through Enforestation", GPCE 2012. It shows how we can bridge the relatively linear structure of non-() programs to the tree structure of S-expressions. Specifically, the bridge is called "enforestation". It sits roughly between the reader and the expander, but enforestation needs to be interleaved with expansion to get the level of expressiveness that Racketeers would expect.

というのが主張の主眼のようだ。つまり「カッコが多いのとオペレータが必ず前置なのは使いにくい」そして「マクロをサポートできるレベルのプログラマブルな非S式構文が可能だという研究結果がある」という二点である。

後者に関してはこちらの論文で、Matthew Flatt自身の共著。Enforestationという具象構文をAST的なものに変換する機能をmacro expansionと繋げることで、非S式でも自然な形でマクロが書ける・使える、ということらしい。

Shrubbery

Racket2はその後Rhombusと命名され、非S式構文についての研究も続けられている。

その中でHonuをベースに出てきたのがShrubbery記法である。こちらの資料に詳しいコンセプトや用例が載っている:

github.com

Shrubbery notation is similar to S-expression notation, but instead of generating fully formed trees, it is intended to partially group input for further enforestation by another parser (e.g., as in Honu). The notation is line- and indentation-sensitive, and the parsed form of a shrubbery imposes grouping to ensure that further parsing is consistent with the shrubbery's lines and indentation.

サンプルコードはこんな感じ:

def identity(x): x

def fib(n):
  cond
  | n == 0: 0
  | n == 1: 1
  | else: fib(n-1) + fib(n-2)

def print_sexp(v):
  match v
  | empty: display("a")
  | cons(a, d):
      if is_list(d)
      | display("b")
      | display("d")

注意するべきはShrubberyは記法であって構文ではない点。

Forms like def, cond, and match are not specified by shrubbery notation, since specifying those forms is up to a language that is built on top of shrubbery notation. Still, shrubbery notation is meant to accommodate a particular kind of syntax for nested blocks (via : and indentation) and conditional branches (via |).

とある通りdefなどのキーワードやブロックの意味論などは未定で、Shrubbery記法の上でしっかり構文を定義してやる必要がある。逆にいうといろんな具象構文のベースにできる記法だというコトで、自作言語を作る分にはなかなか便利そうである。特にLispもMLも抽象構文としてはラムダ計算に糖衣構文がくっついたものなので、この記法はRacketでも使えるだろうけれどMLとも相性は非常に良さそうである。

変更したい点

とはいえ全般的に不満がないかというとそういうわけではなく、自作言語で使う場合はShrubberyインスパイアな構文になりそう。

特に不満があるのがifの形で:

if x
| world
| universe

| ...のコンディションわけがかなり違和感がある。それよりはまだ:

if
| x: world
| else: universe

のような形にしたほうが好み。ただしこれだとcondでいいじゃん、という見方はある。さらにifがポツンと1行あるのは冗長か?

あるいは別案として:

if x:
  world
else:
  universe

とする手もあるかとは思うが(よりPython的)、そうするとブロック構造が崩れているような印象もあり一長一短か。

また、Pythonと違って「頑張ればプログラムすべてを1行で書ける」という余地を残しておくのは結構重要な気がしている(特に関数型プログラミング言語においては)。Shrubberyはそんなニーズも満たしてくれるのだが、その記法についてももう少し洗練させられるのではないかという気がしている。

今後

というわけでちまちまとこの記法インスパイアな構文を考えたりパーサを作ってみたりしている。当面の目的としてはMinCamlあたりにこの構文を被せてLLVMコンパイルできるようにしたい。