エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

ショートコーディングしようっとwww

【基盤開発チーム ブログリレー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は区切り文字で、wWの数で動作を制御します。具体的なコードを見ながら説明させてください。

'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)に適用するという意味になり、この結果もスタックに積まれます(下図の右側)。

動作イメージ1
動作イメージ1

疑似コードで書くとこんな感じです。

const func1 = (arg1) => Out('w')

関数定義が終了した時点で、関数適用部分のスタックは下図のようになっており、定義した関数が最上段に積まれています。

動作イメージ2
動作イメージ2

関数適用部分には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!

エムスリーには、このように偏った嗜好を持つエンジニアであっても受け入れる、懐の深さがあります。 ぜひぜひご応募ください!

jobs.m3.com