STORES Product Blog

こだわりを持ったお商売を支える「STORES」のテクノロジー部門のメンバーによるブログです。

経理からプログラマへ、Lramaの今後、なぜBisonを倒したのか。深掘りRubyKaigi 2023 with spikeolaf & makenowjust 文字起こしレポート vol.2

2023年6月15日に『深掘りRubyKaigi 2023 with spikeolaf & makenowjust』を開催しました。イベントの内容をほぼ全文文字起こし形式でお届けします。この記事は第2部です。 hey.connpass.com

登場人物

ゲスト

  • makenowjust/藤浪 大弥さん
  • spikeolaf/金子 雄一郎さん

STORES

  • fujimura/藤村 大介
  • shyouhei/卜部 昌平
  • hogelog/小室 直

パーサとの出会い

fujimura:金子さんのパートにいきます。簡単にどんな話をRubyKaigi 2023でしたか紹介していただけますでしょうか?

spikeolaf:ここ2年ぐらい、主にAnd the WorldっていうRubyKaigiの名物コンテンツを見ていると、パーサへの関心というのは高まってきていて、ここ何年かで何が問題かはだいぶ整理されてきてたんですね。ひとつにはerror tolerantパーサというものがこのLSPの時代にはほしい。つまり不完全な入力だったとしても可能な限り情報を残してパースしてほしいという要望が世界的に出てきている。もうひとつは、先ほど藤浪さんもおっしゃってましたけど、色々なハックを積み重ねたパーサなんですね。そりゃ大変だっていう話。

もうひとつはユニバーサルパーサという議論があって、CRubyの文法はRubyにおいて標準というか、それがRubyなわけじゃないですか。でもJRubyをやっている人からするとそれを模倣しなくちゃいけないのも大変。他にもSorbetとか周辺ツールを作るときに、彼らの関心は型チェックとかにあったりするんだけど、最初に作るべきものがパーサになってしまうので、しかもバージョンが出るたびに追従しなくちゃいけなくなったりというのがある中でRuby界における唯一のパーサというものを人々が求めているという流れがある。僕自身は今のBisonの系譜、LRパーサの拡張という形でそれらの問題を解決できるのではないかというお話を今回しました。

rubykaigi.org

fujimura:ありがとうございます。いきなり聞き始めちゃうんですけど、パーサとの出会い、興味を持ち始めた、Rubyを触り始めたのはどういうきっかけですか?

spikeolaf:RubyKaigi 2017、広島の時に遠藤さんがカバレッジのライブラリを行単位だけじゃなくて、例えばブランチカバレッジ、ifでどっちに入ったかの情報であったりとかそういったものを取れるようにしていきたいと言っていて。その時にいろんな位置の情報をVM側に渡さなくちゃいけないっていう課題があったんですね。遠藤さんはカバレッジの方をやるわけだけど、パーサ側から場所を引き渡していかなくちゃいけない、当時はパーサにあんまり細かい場所(の情報)がなかったので、そういったところの対応を誰かやってくれませんかって話がありました。たまたま僕の興味がそこにあったので、やってみたのが僕が初めてパーサに大規模な手を入れた時ですね。

shyouhei:すごい、最近だ。

spikeolaf:その発表は仙台でやったので、2018年かな。だからここ4、5年ぐらいです。

shyouhei:ここ4、5年でやり始めて、もう既にパーサジェネレータも作っているわけですよね。

spikeolaf:そうですね。

shyouhei:だいぶハイスピードで来てますね。

fujimura:改めて考えると5年か?!っていう衝撃がありますね。

hogelog:それ以前に一切パーサ的なものは触ったことはなかったんですか?

spikeolaf:いくつかの言語でパーサコンビネータを使ってみたりとかは当然してますけど、日常使いする言語のパーサを真面目にいじるのはそれが初めてですね。

hogelog:はああ、なるほど。

プログラムとASTとパーサの関係性

fujimura:素人質問コーナーをさせてもらおうと思います。プログラムとASTとパーサ、もうちょっと言うとレクサーみたいなところもあるんですけど、それぞれどういう関係性になっているものなんですかね?

spikeolaf:プログラムが一番定義が難しいと思うんですけど、プログラムは仮にRuby コードの.rbファイルでみなさんが書いてるものと捉えるのであれば、パーサの観点から見るとあれって全然構造化されてない情報なんですよね。エディタで二次元にして改行して見てるから、classがあって、defがあって、こっちにブランチしててみたいに読めるけれど、プログラムの立場からすると全部フラットなdefスペースなんちゃらかんちゃらっていう入力値として入ってくると。このままだと何もできない、後ろの工程が大変なので、ここから構造を取り出す作業が必要なんですよね。これをやってるのがレクサーとパーサと言われてるコンポーネントであって、それが一般的には抽象構文木(AST)という形のデータ構造を返すと後ろの工程が仕事がしやすいっていうのがプログラミングあるある、言語実装あるあるなんですよ。

fujimura:ありがとうございます。全然関係ない質問を思いついたんですけど、ASTじゃないものに落ちる場合もあるんですかね?

spikeolaf:例えばBisonそのものの中のパーサとかは確かASTにあまり落としてなくて、設定ファイルみたいな、Rubyのparse.yってBisonの入力とかLramaの入力なんですけど、あれって構造が単純というかあんまりネストしてない構造なんですね。そうすると、ASTじゃないに近いんだけどもうちょっと木構造とは言わないが、リスト構造に毛のはえたようなストラクチャみたいな塊として内部的には処理するので全然OKってこともあります。

fujimura:なるほど。

hogelog:Luaの処理系をいじってたんですけど、LuaはASTに落としてなくて、いきなりバイトコードに落としてたんじゃないかなという気がします。

spikeolaf:Luaはちょっと読んでないんですけど、多分実用的にはできると思います。あと簡単な電卓を作るときは内部で計算もしちゃって、構造としてもっと単純な状態にしちゃうという手もありますし、やりたいこと次第だと思っています。

shyouhei:そうですね。シェルスクリプトとかはそんな感じですね。一行ごとになっているから一行読んで解釈して実行して、一行読んで解釈して実行してみたいになっている。

hogelog:教科書を読むと出てくるインタプリタってやつですね。

Lramaは他の言語にも使えるのか

fujimura:素人質問なんですけど、金子さんが作られていたLramaはRubyのパーサじゃないですか。他の言語にも使えたりするんですか?

spikeolaf:自作言語をLramaでパーサジェネータしたというQiitaを書いてくださった人はいたのでできますが正解なんですけど。ひとつポイントとしては、Lramaそのものの吐き出すパーサはC実装のパーサを吐くので、それで都合がつくのであれば大丈夫ですって感じですね。

fujimura:つかない場合もあるかもしれない?

spikeolaf:何か例がありますかね?

shyouhei:他のJRubyとかに提供したいよって話になると、やっぱCだけだとねって話になってくると思うので。今後は他の言語を出力するみたいな話が出てくるんだと思うが、アクションをどうするのかっていう重要な問題があるので、なかなか一筋縄ではいかなそうですね。

LRパーサってそもそも何?

fujimura:もうひとつ素人質問なんですけど、LRパーサっていう用語が出てきたと思うんですけど、そもそも何なんだろう?Left to Rightとはってところもわからないなみたいな。

spikeolaf:LLとかLRパーサとか色んな種類があるんですけれど、基本的には文脈自由文法のサブセットに近いものを高速に解析したいっていう願いが大体あの辺はあって、その中でLRパーサもLLパーサも最初のLはLeft to RightのLなんです。何かというと、入力されてきた文字を左から右に一直線に読むことで構文解析が終了するっていうタイプのものを解析するツール。そうじゃないものが世の中にあるんですよ。いったりきたりするような解析をする方法もあったりして、その場合は線形時間とは限らないんですけれど。もう一つの後ろの方についてるLとかRというのは、学術的なことを言うとRightmost derivation 最右導出って日本語では言います。言葉の意味自体は生成規則をどういうふうに展開していったかっていうルールの決め方なんですよね。ただそれは構文解析の論理面であって、パーサをいじったり使ってる側からするとパーサの挙動がだいぶ違うように見えます。

LRは左側を見てある程度右側をバーっと見ていって、どこかまでいったらひと塊にして、これはexpressionだったね、statementだったねというふうに折りたたんでいくような進み方をします。LLは左側のいくつか決まったトークンを見た段階で、これはなんとかだねって決めて解析を続けていくっていうモデルになりますね。

fujimura:なんとなくわかった気がしました。パフォーマンスが問題でLRパーサとかが登場したって感じなんですかね?

spikeolaf:歴史は詳しくないんですけど、線形で解析できるってのは結構重要だったんじゃないかなと思ってますけど。藤浪さん、卜部さん、何か知見があれば。

shyouhei:ごめんなさい。僕もさすがにそういったところがリアルタイムではなかった世代なのでわからないですね、どうなんでしょうね。

hogelog:LRが生まれたっていう流れって、LLだと表現できないものがLR文法だと表現できる?

spikeolaf:LRよりもLLの方が原理的に狭いはずです。LRって左側のトークンからある程度の長さを読めるから、その場に応じてなんだけどLLの長さが長いやつと同じ振る舞いをする。LL(1)とLR(1)を比べるとLR(1)が長いはずです。

fujimura:形式言語をいじるのにやたら詳しい人が2人が集まってるってレアな気が。形式言語というか人工言語をいじるのがうまい人。

makenowjust:どうだったかな。LLではparseできるけど、LRではparseできないものもあったような気がするけど、僕の記憶ですが。

fujimura:完全に僕の好奇心で聞く質問なんですけど、parseできないものもいるってことですよね?

spikeolaf:文法定義を与えた時にそれがLLとかLRに収まらないケースがあるという感じかな。一旦LLとかLRのものだというのが確認できれば、それはparse可能ですね。

fujimura:なるほど、ありがとうございます。

プログラマになったきっかけ

fujimura:全然関係ない質問なんですけど、そもそもなんでプログラマになられたんですか?

spikeolaf:大学を卒業した後、事務職で経理をやってたんですけれど、経理の仕事って割と反復が多いんですね。毎月同じようなデータ処理を行うみたいな。それをだんだん手でやったり、Excelを書くのが嫌になったので、当時はXAMPP。XAMPPって言っても通じないのかな。LinuxMySQLPHPで月次で取ってくるデータを流し込んで、必要な計算を行って帳票を作るシステムを最初の2、3年くらい作ってたんですよ。経理業務の一貫として趣味でやってたんですけど、そうしてるうちにだんだんプログラムを書くのが楽しくなってきて。正直PHPの何かを土日にやろうって気持ちがあんまりなくて、その時にたまたまRubyを知って、Rubyオープンソースになにかやるのは楽しいなと思って、その後紆余曲折あって、Webプログラマを経てこういう仕事をしてるって感じですね。

fujimura:普段はパーサを書いてるわけではないと思うんですけど、どんなお仕事をされているんですか?Rubyのコードを書かれている?

spikeolaf:今はエンジニアリングマネージャなので、基本的には仕様の整理やいろんなプロジェクトの優先度を決定するところに参加していますが、うちのチームはRubyを書ける人がいっぱいいるので、お願いすればOKみたいな感じです。

fujimura:経理の仕事とプログラミングの仕事、繋がっているところがあったりするんですか?

spikeolaf:あーどうかな。今やってるのはB2B向けの仕事ではあるので、業務にちゃんと使われるものを安定的に作って運用していくっていうのは、そういう意味ではずっと繋がってると思います。

fujimura:最初から自分で業務システムを作っていたみたいな感じってことですね。

spikeolaf:そうですね。もうちょっと言うと、うちの父親が母親の実家の工場のそういうシステムをずっとCOBOLでメンテしてるんですよ。

fujimura:おおお。

spikeolaf:こうはならないぞって思ってたんですけどね。

fujimura:なるほどな、ありがとうございます。

Lramaの今後、ユニバーサルパーサへの道

hogelog:CRubyの中でのLramaは今後どうなっていきますか?YARPとか色んなソリューションを各位がやっていきたいという中で、金子さんはどういう心持ちなのかを改めて聞いてもいいですか?

spikeolaf:今のところ決まっている情報としては、次のリリース Ruby3.3にはYARPもLramaも両方入れましょうとまつもとさんが多分パブリックに言っていたと思います。僕としては、僕のアプローチが優れてると思っているので、これを推し進めていきたいんですけど。そのためにはLramaってまだBisonの中でRubyが使っていた機能の互換、同じレベルプラスアルファぐらいまできたので、これをもっといろいろ足していって、Lramaそのものをもっと強化していく必要がありますし、同時にユニバーサルパーサという議論で言うと、parse.yそのものの大リファクタリングをしなくちゃいけない。てあたりが今ある話かなと思っています。

hogelog:なるほど。今言及されたので、ユニバーサルパーサについて聞きたいんですけど、金子さんの発表を聞いていて、まずすごいなって思ったのは、内容がめちゃくちゃ難しいのにわかった気持ちになれるように丁寧に解説してくれていて。ユニバーサルパーサの話がスッと進んでいて、金子さんの発表を聞くとユニバーサルパーサをやったらできるんだなっていうふうに聞こえたんですけども、実際は難しいことがいっぱいあるんですかね?

spikeolaf:いや、今のparse.yをRuby関数への依存をなくすって捉えた時には、もちろんCをいっぱい書かなくちゃいけないっていう大変さはあるんですけれど、やればできると思います。

hogelog:他のやつのアプローチで出てきてた謎が!とかいうのはなくて、ただやればできる、やることはいっぱいあるみたいな感じなんですか?

spikeolaf:いくつかの考慮事項はあるんですけれど、基本的にはCプログラミングによるリファクタリングです。いくつかの考慮事項というのは、さっき言った正規表現周りをどうするかとか、どこまでをユニバーサルパーサに持つか、エンコーディングをどのぐらい持つかとか含めた細かい判断もあるんですけれど、テクニカルにはできると思っています。卜部さん、なにかありますか?

shyouhei:これはできないだろうみたいな細かいところのエッジケースを見てないからわからないんですけど、でも作ってる人ができるって言ってるんだからなんとかするだろうみたいな。parse.yを解釈するだけでも一苦労だけど、それだけで終わらない部分もあるわけじゃないですか、ステートフルレクサーとか。そういったところも頑張らなきゃいけないよねって話ではあるんだと思うんだけど。

spikeolaf:ただステートフルレクサー自体はparse.yの中には閉じているので、メンテナビリティという面だともちろん改善しなくちゃいけないテーマではあるんですけれど。ユニバーサルパーサって意味ではアレは残すこともできますし、そこはそんなに危惧していません。

shyouhei:残しちゃうとあんまりユニバーサルにならないというか。型検証で使いたいんですと言われちゃうと、それは結局Cコンパイラが必要なのかみたいな話になるので。

spikeolaf:いや、ASTが手軽に取り出せるシェアドライブラリがほしいって話だと思っているので。

shyouhei:いけるところまではいけるって感じ。

spikeolaf:はい。中がどうなっているかというのは、究極的にはchar*を渡してASTが返ってくればよいっていうのが一番外形的な話だと思っています。ただやることは無限にあるので興味がある人がいたら、ぜひお声掛けいただけると、手伝ってほしいことはいっぱいあります。

fujimura:手伝ってほしいところをみあげると、どんなのがありますか?

spikeolaf:ユニバーサルパーサの文脈で言うと、今Rubyが提供しているものを剥ぎ取っていく作業になるので、そのサブセットを作らなくちゃいけない。要するにRubyのStringのサブセットのようなものを作らなくちゃいけないとか、そういったC実装が大量にあるのでもし興味がある人がいたらやってほしいです。

Lramaそのもので言うと、Bisonが本来持っていたけど、今までバージョンがちらばっていたせいで入れられなかった機能、使えなかった機能を入れていきたいという意見もある。こちらはRubyのコードなので、パーサジェネレータ自体の実装も興味があれば手伝っていただきたいです。あとは、LramaそのものはRubyなので、RBSの型付けをちゃんとやっていこうというのも同時にやっていて、そういったところをやってみたい方がいればぜひご協力いただきたいです。ざっくりまとめているドキュメントを貼っていただいたんですけど、そういったものがあります。

docs.google.com

fujimura:みなさま、ぜひご協力よろしくお願いしますというところですね。

spikeolaf:はい。

なぜBisonを倒したのか

hogelog:発表の中でも言及はあったかもしれないですが、パーサを何とかするぞとなった時のいくつかアプローチが考えられるわけじゃないですか。発表では最終的なアプローチ までのストーリーを話したと思うんですけど、初期にこのアプローチでいけるぞ!みたいなのをどういう考えでやっていこうと思ったんですか?

shyouhei:さっきの話だと最初はBisonの中で取れるカラムの情報をパーサから引き上げて、Rubyの方にAPIとして提供するっていうのが最初だったわけですよね。そこからどうして自分でBisonを捨てるという話になったのかってことですよね?

spikeolaf:なぜお前はBisonを倒しにいったのかという話ですよね。今回の発表に関する実装を始めた時はエラートレラントを最初にやってたんですよ。一番簡単ではないんですけど、一番パーサそのものに手を入れずに済みそうだったなって直感が当時はあったのでやってみたんですけど、やってくとだんだんBisonの何かをいじらないとって話が出てきたんですね。そこは一旦そこでペンディングしていたんですね、これ以上進むとBison書き直しだぞと思って。いやいや人生そんなことないじゃんって思ったんですけど。

その先に今度はメンテナビリティの話をしばらく考えた時期があって、2011年頃の論文で、一見LRパーサって条件に応じて使うルールを書き換えることができないって思われてるかもしれないけれど、ある程度ステートを増やすテクニックを使うと表層としては文脈自由文法を維持したまま、きちんとそのままできますっていうのを読んだ。こういう方向だったらメンテナビリティの改善ができるな、今のRubyのステートをある程度文法の方に持ってこれるなと思って、いくつか論文を読んで考えていたんですけれど。それでも解決できないような問題がいくつかあって、今回の発表で話したdoの話とかああいうのって難しいなっていうのがあって、うーんって悩んでた時にひらめいてdoってこうやったら解決できるじゃんって言った時に、これはもうパーサジェネレータは自分で書いて、自分で機能をそこに足していくのが一番早いなって正直思った。Bisonに手を入れてもいいんですけれど、BisonはC言語を書くことでやっぱ増えちゃうので、Lramaみたいなものを作って、ジェネレータを作るのが一番最短だと思ったのが去年の10月か11月ぐらいですかね。

shyouhei:去年の10月か11月ぐらいから作り始めたんだ。

spikeolaf:実際に作ったのは去年の冬休みだったんで、12月の冬休み入る直前ぐらいから書き始めてだいたい年明けぐらいに一通りRubyのparse.cを吐くところまではいった感じです。

shyouhei:ひょっとして、RubyKaigiのCfPを作った時にはまだできてなかった?

spikeolaf:いや、その時にはできてました。

shyouhei:すごい早さで作っている。Rubyのparse.cと同じものを吐くっていうところが難しい気がしていて。でもそうか吐いたもののdiffを取ればわかるか。

spikeolaf:そう、逆にゴール設定としてすごくクリアなのと、Rubyが使っていない、もしくはRubyが前提として置いている機能はそのまま取り込んじゃえばいいから、Bisonの機能の全部を作る必要がないんです。そういうところは端折っているので、ゴール設定としては楽でしたね。

shyouhei:なるほどですね。

hogelog:今後LramaはBisonの知見も吸いとりつつ、今はないけどBisonのここにあるやつがほしいとかはあると思うんですけど、そういうのも含めBisonともかけ離れていくんですか?

spikeolaf:そうですね、Bisonにない機能をつけていくことになるのでBisonとは異なるものにだんだんなっていく、現時点でもある程度そうなっていると思っています。別にBisonだけではなくて例えばOCamlという言語で書かれているMenhirっていう同じようなLRパーサジェネレータであるとか、あとはLemon LALRのパーサジェネレータにもそれぞれそういう機能はたしかにほしいよなというコンセプトの機能が入っているので、機会があれば取り入れていきたいなと思っています。

shyouhei:世界のパーサジェネレータみたいなやつがいろいろあるんですね。

spikeolaf:パーサジェネレータ業界は狭いんですけれど、それぞれそこにしかないタイプの機能があるんですよね。横の交流がないのかもしれないですけど。

fujimura:横の交流は面白そうですけどね、集まったら。

質問を読みます。

「error recovery導入のブランチがまだmasterに入ってなかったと思うんですが、何か検討中のことがあったりするんでしょうか?」

spikeolaf:単純に僕の手が他で塞がっているというのがあって、もう少しparse.cの細かい部分の書き直しが必要なのと、今コンフリクトしちゃってると思うのでそれを解消したりしなくちゃいけない。細かいのはありますけど、大筋あれで一旦入れて大丈夫だと思います。

fujimura:ありがとうございます。

いつコードを書いてるんですか?

shyouhei:この拘束時間でたくさんコードを書くのはどうやっているのかっていうところが一番の疑問で、昼間の仕事は違ったことをやってらっしゃると思うんですけど、一体どういうタイミングで論文を読んで、どういうタイミングでコード書いたりしてるんですか?

spikeolaf:だいたい業務が夕方に終わってから、夕飯を作るぐらいまでの間はコードを書いてるのと、土日のだいたい半分ぐらいはコード書いてますね。

shyouhei:くらいのやつだけでこのくらいのアウトプットを出せる、すごいな。

spikeolaf:週に15時間とか20時間いかないかな、くらいの時間でやってます。

shyouhei:すごいなぁ。僕なんか論文を読んでて途中ご飯で途切れちゃうと最初から読み直さないと何もわからないみたいな感じになる。ある程度固まりで進めるところ、きりがいいところまで進めないとちょっと無理みたいになっちゃうんだけど、そういうことはないですか?

spikeolaf:そういう意味では論文もアドホックに読んでいてコンセプトだけ抜き取ってくる時とか。僕は自分で論理を書くっていうフェーズではないので、ある程度理解したら実装してみて、Rubyで上手くいくか、上手くいくならとりあえずOKとか。副作用がないかとかっていうサイクルでものを動かすので僕自身は十分なんですよ。

shyouhei:今はそうかもしれないけど、最初の方とか大変じゃないですか?何もないところからパーサを作るのと、パーサジェネレータを作るのって一段メタじゃないですか。

spikeolaf:そうですよ。

shyouhei:メタな部分をよいしょって登るところは大変だったと思うんですけど、そんなことないんですか?

spikeolaf:パーサジェネレータの大変なところは2か所あって、1つはlookahead setをどういう風に計算するかは論理が複雑なのでがっつり時間をとって読みましたね。もうひとつは、テーブルの圧縮方法をBisonと揃えないといけなかったので、Bisonのコードをちゃんと見ましたね。

shyouhei:というのを仕事と並行で、趣味でやってるんですね。

spikeolaf:冬休みが結構あったので、その間コードを書いたり、論文を読むのに集中できたので、まとまった時間がとれたのでよかったです。

fujimura:冬休みはそれにマインドシェアを多く割いて一気にやったんですね。

spikeolaf:そうですね、それをやってるかRTA in Japan見てるかみたいな生活でした。

fujimura:今から冬休みだったら何をしますか?

spikeolaf:今この状態でってことですよね。今だとparse.yをもうちょっと手を入れたいので、parse.yにある程度ベースとなる実装を入れたいなっていうのがまずあって。その後はちょっとLramaの方をやるか、いくつか温めてるアイディアを実験するかは悩んでます。

fujimura:なんか差し支えなかったら温まってるアイディアのことを聞いてみたいな。

spikeolaf:ひとつは今回の発表ではなかったんですけど、lex_stateと言われてるレクサーの状態をどうにか管理できるようにしないといけなくて、今ってレクサーもパーサもレクサーの状態をいじるんですよ。これをパーサ側に全部引き上げればもっと宣言的になると思ってて。

fujimura:レクサーの部分がってことですか?

spikeolaf:そうです。だから構文のルールの中でレクサーの状態が変わるような表記になればレクサーの中ってCで書かれてるから、すごく読みづらく予測しにくいんですよね。でもパーサの記述っていうのはもうちょっと弱い計算で済むので、そっちの方がよりコントロールしやすいだろうなと思っていますね。

fujimura:ありがとうございます。

shyouhei:金子さんの方向性としては、手書きのパーサコンビネータみたいなやつよりもparse.yみたいなやつに寄せていった方が読みやすいっていう発想なのかもしれないですね。今聞いてて思った。

spikeolaf:究極的にというかshift/reduce conflictが嫌というか、嫌う方も多いと思うんですけれど。

shyouhei:まつもとさんが大嫌いなんですよね。

spikeolaf:あれが出ること自体が嫌、解消の仕方がわからないしみたいな。

shyouhei:shift/reduceは(解消)しなくても一応動く。

spikeolaf:Rubyの場合は解消するっていう前提があるんですけれど、LRパーサみたいなやつの良さっていうのは構文を定義する人間、これは仮にまつもとさんかもしれませんけれど、構文を今後追加していくときにあんまり変な構文って足せないんですよ。なぜかというと、どこで切り出して、どこまでもreduceをかけていいかがわからないときは基本的に全部shift/reduce conflictというエラーとして出てくるわけじゃないですか。人間にとって理解しやすい、人間が理解上間違えないような構文を強制されるんですよね。っていう特性を僕は捨てたくないんです。

shyouhei:shift/reduce conflictは構文が二通りに解釈できるときに、どっちに取ればいいかわからないっていうやつなんですけど、そういう風なのを手書きのパーサだと書けてしまいがちだけど、parse.yだと書きづらいっていう話ですよね。

spikeolaf:ですです。LRパーサだとそういうときは基本的には全部検知してくれるので。その上でどっちにするっていう手はあるんですけど、まず一旦そこで検知してくれるので。

shyouhei:なるほどね。

僕たちがLRの良さを理解していなかっただけ

fujimura:質問をいただいています。これは散々聞かれたような気もするんですけど、パーサの話は今回のRubyKaigiで2個新キャラが登場してたわけじゃないですか。どういう風に 違いを見ていらっしゃるのか、あとは競争がいい感じに始まっている状況をどう感じていらっしゃるのか。

spikeolaf:競争なのかっていうのもあるけど、個人的には世界の潮流という言い方は変ですけれど、手書きに行った言語っていうのは結構あって、Goも最初はyaccかBisonを使っていたはずなんですけど、2006年に手書きに移った。GCCが手書きに移った時期が2000年代のはじめにあったんですけど。それに対して、いやいや、僕たちがLRの良さを理解していなかっただけじゃん、僕たちがLRに機能を足してなかっただけじゃんっていう立場なので。Rubyという明日からみなさんのRailsを動かす基盤となる言語で行われているっていうのは僕は非常に面白いと思っていて、そういう意味で良いことだと思っています。

もう一つの質問で言うと、僕はLramaを作って推進しているので、もちろんLramaが残るのがいいと思っています。ただ一方でこういうイベントや質問をいただくことで、手書きとか手書きじゃないものジェネレータとかっていうのはどういう特性がそれぞれにあって、どういう良さがあるっていうのが話す度に再評価される、良し悪しが語られると思うんですよ。それが一番パーサもしくはパーサジェネレータの発展にとって良いことなんじゃないかと思っています。

fujimura:健全な競争って感じですね。

spikeolaf:そう思います。

fujimura:なんでLRパーサリバイバルみたいな感じになっているんですかね?

spikeolaf:イギリスのLaurence先生とかアメリカでもlangccっていう実装を作った人がいて、僕の見えている範囲では何人かが2020年代にLRパーサ推しの人が出てきたんです。どういう機序があったかはわからないんですけど、何かその人たちは思ったんだと思うんですよ。

これは僕が言うと悪口に聞こえるかもしれないけど、どっちの論文にも手書きパーサはそれなりにやりたいこといっぱいできるけれど、メンテナンスが大変であったり、あと今までガードレールをひいていた分外しちゃうことになるので、その結果例えば特定の言語をディスる気は全くないんですけれど、思わぬところで変な構文が入ることが実際にある。Rubyはそんなにないんですけど、型とかも一緒に構文の中に書く言語だと型の中に式に近いものを書くケースが結構あるんで。そういうところで思わぬ解釈の仕方をしたりとか、人間からするとなんでそうなるの?みたいな文法が通っちゃうこととかがあったり。もっと言うとなんでそう解釈されるの?っていう文法が通っちゃったりするのは実際にいくつかあって、そういったものをどう捉えるかかなと思っています。

fujimura:コメントにもあったように「ガードレールになってくれている」みたいなところなんですかね。ありがとうございます。

ここ何年かで一番感動したdiff

fujimura:金子さんは藤波さんの発表を見て、どんな感想でしたか?

spikeolaf:藤波さんの発表のスライドを最初に見たときにギョッとした。これを発表するのかと思って。発表自体はまだ見れてないんですけれど、藤波さんが最初にキャッシュをやるときの実装をGitHubで見たんですけど、この差分でいけるんだってびっくりして。コードの差分の変更がすごいきれいだなと思って、ここ何年かで僕が一番感動したdiffでしたね。

makenowjust:ありがとうございます。実際そういう狙いがあって、DFA型の正規表現エンジンを頑張って実装すれば線形になるっていうのはわかるんですけど、なるべく差分が少なく互換性が上手く保障できるようなやり方としてメモ化を選んだので、そのあたり見ていただけたのはすごい嬉しいです。

shyouhei:読めるっていう驚きですよね。

spikeolaf:そうそうそう。わからないハックが入っててできてるじゃなくて、読めるぞみたいな気持ちになりましたよね。

fujimura:ありがとうございます。

spikeolaf:僕がまだちゃんと理解できてないんですけど、Ruby正規表現エンジンを書き直して使いたいっていう話であってますか?

makenowjust:今のやつをメモ化でやっていくとどうしてもOnigumoの構造に引っ張られてしまうので、新しいものを最終的には作る。多分、ほんの数パーセントの範囲を広げるためにやらなきゃいけないような気がしていて、ただ本当にその数パーセントを広げる意味があるのかをちゃんと考えなきゃいけないなという気もしています。

spikeolaf:わかりました。

Rubyの文法で一番この野郎と思うもの

spikeolaf:「今のRubyの文法で一番この野郎と思うのはどれですか?」という質問ですが、やっぱり一番衝撃だったのはさっき言った正規表現で変数束縛するところのコードは、あーなるほどねって思ったのと、あと変数の有無でASTが変わる箇所が何箇所かあって。lex_stateがそもそも変わるんですけど、あの辺はちょっとキツいなというか、わかるんだけど大変だなっていうのがあります。クソって言うんだったら、エンドレスメソッドディフィニションが僕は嫌いで。書く側としてはいいんだけど、さっき言ったようにLRパーサって左側と右側の終端で基本はくくるんですよ。エンドレスにしたらくくれるわけないじゃんって思いません?っていうのがちょっとあったので、あれは難しいタイプの構文だなって思っています。

fujimura:一見普通だが思っていたより大変みたいなのもあったりするんですか?

spikeolaf:一見普通だけどで言うと大体全部大変なんですよね。Rubyの文法って式を読み始めたか式を読み終わってるかとかを実はlex_stateでケアしてるんですよね。自然に見えるのがより厄介だと思ってて、僕たち書くときにあれを認識できてるんですよ。今回LTの方で話したんですけど、<<って書いたときに、これはシフト演算かもしれないし、ヒアドキュメントの開始記号かもしれないみたいなのを僕たち人間は何も苦労せずに読めるんです。Rubyはそれを実現してるんですよ。すごいなって思う反面、これはステートの塊だよねって思うとゾッとするみたいなのがあります。

fujimura:なるほどな。卜部さんが何か言いかけようとしてる気がする。

shyouhei:いや、大変ですね。僕がRubyっていうプログラムを初めて読んだ頃はRubyがまだ1.8とかだったので、その頃でもすでにparse.yは結構きつかったけど、それ以来何十年も経って徐々に降り積もっていってどんどん大変になっている感じですかね。parse.yって文法に名前を付けてサーブエクスプレッションコールとかできないんですよ。だいたい全てのものがコピペで行われているので、これと同じものを前に見たんだけどちょっとだけ違うみたいなのが大量にあって。どう見ていけばいいのか途方にくれますね。純粋に量が多いのでちょっと大変。

spikeolaf:ヒアドキュメントは特殊だなって思います。行指向が強いじゃないですか。いきなり次の行に飛んで戻って、またその後にまた行に飛ぶみたいに書けたりするので、ヒアドキュメントはわりと特殊だなって見てて思います。

shyouhei:ヒアドキュメントはRubyのISOを昔作った時に、他の文法のところはスルスルと書けたんだけど、ヒアドキュメントだけISOの文法の定義が超大変だった。

spikeolaf:ですよね。

fujimura:読む方も大変なんですか?構文解釈する方も。

spikeolaf:レクサーに頑張らせてますね。行を変えて、それを持っててみたいなことを繰り返さないといけないって意味では大変かな。あとは改行を読んで飛ばしたり飛ばさなかったりする言語仕様なのでそれも面白いというか特徴だなって思ってます。

fujimura:逆にこの言語は楽みたいなのもあるんですか?

spikeolaf:構文解析において楽ってことですか?一番簡単なのは一番左端のトークンを読んだ時にその後来るものが全部わかる言語は簡単だと思います。

fujimura:それに近いものでいうとどういうものがありますか?

spikeolaf:パッと出てこないんだけど、(コメントを見ながら)LISPはたしかに簡単ですね。すごく簡単な気がします。

shyouhei:最近でこそエンドレスメソッドデフィニッションとか入ったけど、Rubyっていうのは必ずdefから始まってendで終わるとか、classから始まってendで終わるとか、先頭のキーワードを見て対応するendを探すっていうので昔はすごいシンプルだった。

fujimura:(コメントを見ながら)あ、FORTHなるほど。スルっと質問コーナーみたいになってきたんですけど、一旦金子さんのパートを終わりにします。金子さんありがとうございます。


第3部に続きます。

深堀りRubyKaigi 2023 文字起こしレポート一覧

イベントのアーカイブYouTubeでも公開しています。 www.youtube.com




\ STORES では一緒に働くエンジニアを募集しています /

jobs.st.inc