【基盤開発チーム ブログリレー1日目】
こんにちは。エムスリー エンジニアリンググループの高島(id:rst76)です。 基盤開発チームでもブログリレーをすることになり、なにか仕事の話をできないかと思ったのですが、なにも思いつかなかったので、今日は一般的なコーディング技術について話をしたいと思います。
サービスを健全に維持する上で、コードの保守性が重要だということは論を俟たないでしょう。 特にコードを簡潔に保つことにより、可読性は高まり、長い年月を経ても容易にコードを維持できます。 そのような観点から、コードを簡潔に短く書くショートコーディングの技術はエンジニアにとって非常に重要だと言えます。
また、コードの簡潔さとともに忘れてはならないのが、言語自体の簡潔さです。 たとえばRubyは素晴らしい言語ですが、このようなクイズを解けるだけの素養が求められるというのは、やはり言語そのものが複雑すぎると言えないでしょうか。
そこで今回はGrassという言語を題材に、いかに簡潔なコードを書くかということを議論したいと思います。
Grassの概要
Grassが生まれたのは2008年なので、もうすぐ15周年(!)になる歴史ある言語です。
コードに利用する文字はw
, W
, v
の3つだけ、言語仕様はWebページ1枚という簡潔さです。
インタプリタもいろいろな言語で提供されているので、ぜひダウンロードして手元で動かしてみてください。
構文も単純で、関数定義と関数適用があるだけです。
wwwwwWW ... wwWw v wwWWwW ... wWw v WWWwwwWw ... wwWWw v wW ... <--- 関数定義 ---> <-- 関数定義 --> <--- 関数適用 ---->
v
は区切り文字で、w
とW
の数で動作を制御します。具体的なコードを見ながら説明させてください。
'w'を出力しよう! その 1
'w'の1文字を出力するコードはたとえば、以下のようなものです。
wWWwwww v Ww
v
の左側の関数定義から見ていきます。最初にw
が1つあることで、この関数の引数が1つであることを示しています。
Grassには w, Out, In, Succ という4つのプリミティブがありますが、それらに加えて引数が、初期状態でスタックに積まれます(下図の左側)。
各プリミティブの説明は言語仕様に記載されていますが、ここではOutが出力関数、wが文字'w'を表すことだけ知っていれば十分です。
W
が2つ、w
が4つ連続しているので、上から2番目の関数(Out)を上から4番目の値(w)に適用するという意味になり、この結果もスタックに積まれます(下図の右側)。
疑似コードで書くとこんな感じです。
const func1 = (arg1) => Out('w')
関数定義が終了した時点で、関数適用部分のスタックは下図のようになっており、定義した関数が最上段に積まれています。
関数適用部分にはW
が1つ、w
が1つ並んでいます。これは1番目の関数を1番目の値に適用するということで、以下のような疑似コードと同等です。上で定義したようにfunc1では引数を利用していないので、引数が何であっても構いません。
func1(func1)
'w'を出力しよう! その 2
たとえば以下のように関数を定義しても、同じ結果が得られます。
wWWw v Wwwww
これは以下の疑似コードに相当します。
const func1 = (arg1) => Out(arg1) func1('w')
またGrassには
プログラムの終わりに当たったら,スタックの一番上の値を関数として取り出し,その関数自身を引数としてその関数を呼び出します.
という仕様があるので、前節で最初に例示したコードの関数適用部分は、省略することもできます。ちょっと短くなりました(関数定義は省略できません)。
wWWwwww
'x'を出力しよう!
最小限のプログラムは書けたので、少しだけ工夫してみましょう。'w'ではなく'x'を出力してみます。 Grassのプリミティブの1つであるSuccは、入力された文字の次の文字を返してくれる関数なので、こんな感じのコードで実現できそうです。
const func1 = (arg1) => { const const1 = Succ('w') Out(const1) }
Grassだとこう書けるということを、みなさんはもう理解されているのではないでしょうか。
wWWWwwwwWWWw
echoをしてみよう!
出力ができたので次は入力ですね。入力された文字列をそのまま出力するechoを書いてみます。
疑似コードはこう。
const func1 = (arg1) => { const const1 = In(arg1) Out(const1) arg1(arg1) } func1(func1)
関数定義内の1行目で入力を1文字読み取っています。Inの引数は何でも構いません。それを2行目で出力します。 3行目がポイントで、引数を再帰的に呼び出しています。最初にfunc1自身を引数に設定してfunc1を呼び出せば、func1の呼び出しが無限に繰り返されるので、入力が続く限り出力も続きます(止まりません)。
Grassだとこんな風に書けます。
wWWWWWwWWWwWWWwww
おまけ
さぁ、これでGrassを書くのに必要な情報はほぼ揃いました。ぜひご自身でも挑戦してみてください。Hello, world!とかオススメです。 ショートコーディングと言いながら、短く書く工夫についてはあまり触れられなかったので、以下のコードも紹介しておきます。
wwWWwWWWwvWwWwwWwwwwWwwwwwww
このコードは'w'をちょうど16個出力します。どうやって実現しているか気になった方は(そんなの分かっているという方も)、ぜひカジュアル面談にお越しください。
We're Hiring!
エムスリーには、このように偏った嗜好を持つエンジニアであっても受け入れる、懐の深さがあります。 ぜひぜひご応募ください!