[雑多] ピカチュウでもかけるプログラム言語を作った

先日、こんなネタツールを作りました。

Pikkal - ピカチュウのためのプログラム言語

本日はこの謎ツールのリリース記念として、なんでこんな意味不明なものを作ったのか、というお話をしたいと思います。

きっかけ

私くらいの熟練ぼっちともなると、ゴールデンウィークにやることないんですよね。分かる人にはわかると思いますが。しかしせっかく10連休という、ちょっと遅めの春休みを無駄にするのもアレなので、久しぶりになにか作ろうかな、と思ったのがきっかけです。せっかく作るのだから、普段使わない技術を使ってみようと思いたちいろいろ考えを巡らせてみた結果、ちょっと前に触っていたRustを使って本格的に動くものを作ってみようと思い立ちました。Rustは私が初めて触った頃に比べてかなり安定していましたし、TypeScriptとかC++とかScalaとか、普段使っている言語から少し離れてその思想を学ぶのも悪くないでしょう。
 そんなわけで作りたいものより先に使う技術を決めてしまいましたが、新しい言語を学ぶ際にはその処理系で別の言語を実装してみると一通りの機能に触れて幸せになるのは経験上なんとなくわかっていました。そうなると、簡単に実装できる言語がよいのですが、その点ではBrainf*ckとか独自にでっちあげたスタックマシンあたりが候補に上がってきます。今回はBrainf*ck同様難解プログラミング言語の仲間であるWhitespaceを選びました。今回はというより今回も、ですが。
 話は変わりますが、GWの後半は実家に帰りました。私は普段テレビを見ないのですが、実家に帰るとテレビがついているのでそれが映し出す映像が意識せずとも目に入ってるくわけです。夕方だらだらと過ごしていたところ、偶然ポケモンが放送されていたんですね。後ほどWhitespaceがどのようなプログラム言語なのか少しお話しますが、ピカチュウがその言語の設計において非常にマッチしているわけです。そんなわけで今回の謎言語が生まれました。

Whitespaceって?

難解プログラミング言語において、圧倒的な知名度を誇る言語はやはりBrainf*ckでしょう。8つの命令を用いてプログラムを記述する、非常にシンプルな仕様ながらチューリング完全なプログラム言語です。実装も簡単なため、たくさんの亜種が生まれることになりました。
 Whitespaceも難解プログラミング言語の一種であり、スペース/タブ/改行(以下それぞれS/T/Lと記載)の3つのトークンを用いてプログラムを記述するプログラム言語です。つまり印刷するとコードが全く読めないというネタ言語なのですが、処理系自体はシンプルなスタックマシンであり、かつ実装も非常に簡単なため、私は言語処理系の基礎を学ぶに適している言語だと思っています。ネタとしても面白いので教育分野でもっと使われればいいのに。
 さて、ここでなぜピカチュウと相性がよいのか、という疑問にお答えしておきましょう。簡単です、ピカチュウが「ピ」「ピカ」「ピカチュウ」という3つの字句を用いて意思疎通することが多い、という超適当な先入観が答えです。しかし実際のところ「ピカチュウ語」で検索してみると、やはりこの3語の組み合わせ(間に長音符などが入ることはあります)が圧倒的に多いようでした。Brainf*ckは8語も使用しなければならないため、字句3つで済むWhitespaceのほうが相性がいいのは一目瞭然です。ちなみにOok!という、同じく3語で記述可能なBrainf*ckの亜種もありますが、こちらはその3語を2つの組み合わせで使うことで、3^2=9通りの字句を実現するものです。ぶっちゃけあんまり面白くありません。
 そういった事情から、Whitespace+ピカチュウという試みが始まりました。

目的

目的は、とにかく使いたい技術を詰め込むこと。使用した言語はRustであり、WebAssemblyへコンパイルしてブラウザ上で動作させています。WebページはTypeScriptで書いてます。レスポンシブデザインにして、PCでもスマホでもいい感じのデザインになるようにしました(Whitespace実装するよりも時間かかりました)。ホントはサーバサイドもいろいろやりたかったんですが鯖の用意が面倒だったのでやめました。面倒だったらやめれるのが趣味の良いところですね。Whitespaceの実装は汎用化し、モジュールとして切り出しました(あとでgithubにあげておきます)。

Rust

RustはFirefoxでお馴染みのMozillaが開発しているプログラム言語です。一言で言えば「よい」。長年C++を使ってきた私からすると、そこまで学ぶのが難しくなく、かつC++でコードを書く人が気をつけなければならないことをコンパイラさんがうまくやってくれるため、精神が非常に安定します。const厨としては変数がデフォルトで不変なのはとても心強いですし、パターンマッチによってプログラムを書けば書くほど気持ちよくなれます。またRustの大きな特徴の一つであるライフタイム(オブジェクトの寿命を管理する仕組み)も、ダングリングポインタ量産が得意な私のエンジニアとしての生命を支えてくれています。
 とはいえ、ライフタイムは実際に使ってみると思い通りにならないことも多々ありました。C++ならこうかけるのに、みたいなのも最初はありましたが、コンパイラがとても親切なので原因はまぁまぁわかりやすい(少なくともVC++の謎メッセージの5000兆倍はわかりやすい)ですし、すぐに慣れます。平成最後の夏、Rustを学んでみるのはいかがでしょうか。

WebAssembly

WebAssemblyとは、ブラウザ上で動く仮想マシンです。JavaScriptはもはやブラウザにおける仮想マシンのような扱いになっていますが、やはりネックとなるのは処理速度でした。そこで古の闇技術asm.jsが生まれるのですが、やはりJavaScriptというテキストである以上ファイルサイズが大きく、またパースにも時間がかかっていました。そこで生まれたのがWebAssemblyです。予めコンパイルされ、ブラウザ上で実行可能なバイナリ形式でプログラムを実行することが可能です。2018年7月現在主要なブラウザでサポートされています。言わずもがなInternet Explorerは対応していませんが、IEは今すぐにでも滅ぶべきなのでサポートする必要はないでしょう。WebGLなどとの組み合わせで、ブラウザ上でも3Dバリバリなゲームなど、リッチなコンテンツの開発が可能になります。
 余談ですが私は以前(非公式)のWebAssemblyのロゴがかっこよくて好きです。正式なやつはちょっとどころじゃなくダサいです。

独自機能の追加

Whitespaceはチューリング完全です。プログラム言語としては申し分ありません。しかし、定義された命令だけでは面白いプログラムは書けないでしょう。なぜなら、乱数を発生させることができないからです。したがって、Pikkalでは乱数を生成させる命令と、現在時刻をUnix時間で取得する命令を拡張命令として実装しました。これにより、サンプルコードにある数当てゲームのような、乱数によって挙動が変わるプログラムを記述できるようになりました。

結構苦労した

さて、ここからは大変だった部分を少し書きます。

ブラウザ上で動かす

これ結構苦労しました。ググればまぁまぁ情報は出てくるんですが、それでもEmscriptenに比べれば少なめです。Rustのクレートの中にはブラウザ上では動作しないものがいくつかあり、それらを回避するのに少し時間がかかりました。具体例をあげると、入出力はもちろん、乱数や時間取得系のクレートも動作しないので、そこはJavaScript側から入力してあげる必要があります。また、CUIであれば標準入出力は待機となりますが、ブラウザ上では処理を入力→サスペンド→任意のタイミングでレジュームとなるので、VMの状態を一時的に保持しておく必要があるなど、多少複雑化する部分もありました。

サンプルコードの実装

相当時間かかりました。Hello Worldなど簡単なものは実装も楽なのですが、実行しても面白くありません。ある程度乱数要素のあるものを作りたかったので、Hello Worldに加えて数当てゲームを実装しました。また、Whitespaceは再帰処理が可能なため、再帰のサンプルとして有名なフィボナッチ数やハノイの塔なども用意しました。これらのプログラムは、すべてハンドアセンブルしています。最初にJavaScriptでコードを書き、それをスタックマシンに置き換えていきました。Whitespaceには一応ヒープがあり、変数を使うこともできるのですが、基本的にはスタックのみを使って作るようにしてあります。

Webページを作成

デザインセンスゼロマンとしては、一番苦労したのがここです。PC版だけならそうでもなかったのですが、モバイル版を無駄に頑張ったのでそこで時間食われてます。IEがオワコン化した今、次なるIEポジションになりつつあるSafari君が結構足を引っ張りました(特にiOS版)。ちなみにピカチュウのカラーパレットを参考に作っています。右上のメニューボタンはピカチュウの背中のつもり。

無駄なものを作る、ということ

さて、ここまでPikkalの実装に関していろいろとお話してきました。本来であればGW中にある程度作り上げるつもりだったのですが、いろいろあって3ヶ月ほどかかってしまいました。私も一応社会人をやっており、そこそこ忙しい毎日を送っているため、作業時間は休日にしか取れませんでした。貴重な休日をなに馬鹿なことに費やしているのか、と思うかもしれませんが、友だちがいないと他にやることがない実際役に立たないものを作るのって超楽しいんですよね。そして作るのが楽しくないと新しい技術に手を出したり、完成まで持っていくのってかなり難しいと思います。趣味だと締切とかがないのでなおさらグダってしまうので大変です。
 作られたものは無駄かもしれませんが、それを作るまでにかかった時間や技術は無駄にはなりません。私の場合仕事でRustを使うことはないと思いますし、ましてやWhitespaceを実装することなんてないでしょう。しかし、作る過程で得た知識経験は別のものを作る際に利用できます。普段はC++でゲームを作るお仕事をしていますが、一つの言語だけを利用してしまうとその言語で表現可能な実装に偏ってしまうため、様々な言語とその思想を学ぶことは非常に価値があります。
 そして、作っているものが無駄だけに、面倒になったらやめやすい、というのも一つのメリットだと思います。思いつきで作ってダメならやめればいいんです。私もネタを思いついては作ってを繰り返していますが、95割は完成までたどり着いていません。今回公開までたどり着いたのは奇跡に近いです。でも超楽しいのでそれでいいんです。ぐぐってみると似たようなサービスがたくさんヒットすることもあるでしょう。でも車輪の再発明上等です。
 みんなももっとたくさん時間を無駄にして、何の役にも立たないものをたくさん作りましょう!

0 件のコメント :

コメントを投稿