Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ken-okabe/4cc2f0ef4ce30bce805e to your computer and use it in GitHub Desktop.
Save ken-okabe/4cc2f0ef4ce30bce805e to your computer and use it in GitHub Desktop.
関数型プログラミングに目覚めた!IQ145で美少女JKの先輩から受けた特訓 5日間
##登場人物
**セキヤ**
高1男子。都内の進学校に通っている草食系チェリーボーイ。
プログラミングが趣味でコンピュータ部に入部した。
**サクラ先輩**
高2女子。IQ145の知能を持つ美少女。セキヤを厳しく指導する。
コンピュータ部では、いち早く頭角を現し、現在は高3部員を差し置いて部長として君臨する絶対的存在。
プログラミングスキルは『神の眼』と呼ばれる全能レベルにまで到達していると一部では噂されているが、サクラのコードを読み解けるだけのスキルをもつ人材が部内にいない為、今のところ真相は不明である。
[TOC]
##**Day1** それは「関数型プログラミング」という新世界の幕開けだった
###ラブ・ストーリーは突然に
**「ずいぶんとダサいコードを書いてるのね。」**
不意に背後から声をかけられ振り向いて見ると、透き通るように白い首筋が目の前にあった。
「はっ、サクラ先輩!」
スラリとした長身を前かがみにしてモニターを覗きこむように見ている長い黒髪の少女の存在をセキヤが理解するまでに一瞬の間が必要だった。
放課後の電子計算機室。コンピュータ部の活動に自由に使用して良いことになっている。今日は他の部員は誰もおらず、セキヤ一人きりで黙々と作業をしていたのだが、いつのまにかコンピュータ部の部長であるサクラが様子を見に来ていたようだ。
「セキヤ君は何のプロジェクトやってるんだっけ?」
セキヤの反応を意に介することもなく同じ姿勢でモニターに表示されたコードを頭上からの冷たい目で凝視したままのサクラ。
微かに甘い良い香りがしてくる。実際、お互いの息がかかりそうなほどの至近距離にセキヤは明らかに動揺していた。また自分の両方の耳は赤くなってしまっているのだろうな・・・先週サクラになじられた事を思い出しながらセキヤは精一杯の平静を装って答えようとする。
「えっと、今は何もやっていないです。プログラミングコンテストの地区予選に向けて過去問に挑戦しているところなんです。」
「あーそうなんだ。だけどこんなダサいコード書いてたら絶対勝てないよ。残念だけど。」
今日のサクラはセキヤの動揺をなじることよりも、セキヤが書いたコードのほうに関心があるようだ。おかげで少し余裕を取り戻しながら、セキヤは言ってみる。
「えー?そんなにひどいですか。」
「ダサいわね。まったくお話にならないわ。」
見下すような冷淡さでバッサリと切り捨てられる。
「そうですか・・・どこがまずいのでしょうか?」
セキヤはこんな風にサクラと何気なく会話できている自分が嬉しい。内心は小躍りしたいような気分なのだが、表向きは平然と会話を続けられることが嬉しい。
「教えて欲しいの?」
居直ってはじめてこちらを見たサクラの知的な目がキラリと光る。
のぼせ上がっており、もはや目の前のコードやプログラミングコンテストの地区予選のことなどはどうでもよくなっていたセキヤではあるが、ただただサクラとのこの時間を持続させたい一心で上辺の調子を合わせる。
「教えていただけると嬉しいです。」
「地区予選はいつだったっけ?」
「来月の頭くらいですね。」
少しのあいだ思案した後、サクラはおもむろに言う。
「まあ、ギリギリ間に合うかも。**ちょっと特訓してみる?**」
自分の熱心さが部長のサクラに認められたのだろうか?厳しいが美しく、部員への面倒見もいいサクラは絶大な人気がある。
雲の上のような存在であるサクラからの思ってもみないオファーにセキヤは心がうち震えるようだった。
 
この高校に入学できてよかった。コンピュータ部に入部して正解だった。今、この瞬間、僕は青春を謳歌している!セキヤは自分の幸運と幸福を噛み締めていた。
###0から9までの数をすべて足すコードを書け
サクラは無造作に近くにあった椅子を引っ張ってきて、セキヤの隣に姿勢よく座った。
「セキヤ君は、プログラミング言語は何を使いたいの?」
再びサクラと寄り添うような格好になってしまった上に至近距離で自分の名前を呼ばれて著しく混乱してしまっているセキヤだが、なんとか振り絞るように答えた。
「JavaScriptです。」
「良い選択ね。ではまず、基本的なところから始めてみましょうか。
**0から9までの数をすべて足すコードを書いてみて**?」
「はい。余裕です!」
問題に向かえば、セキヤは不思議と心は落ち着く性分だ。
躊躇なく書き慣れたコードをタイプしていった。
```
var s = 0;
for (var n = 0; n < 10; n++)
{
s = s + n;
}
console.log(s);
```
>45
「ほら、どうです!こたえは45。」
軽い達成感とともにセキヤは、サクラへ誇らしげに言う。
「動くだけで、やっぱり超ダサいわ。」
「え?」
「今どきこんなダサいコードを書いているようでは地区予選で他のプレイヤーに瞬殺されちゃうわね。」
「そうなんですか!?でもどこがダサいのかさっぱりわかりません。先輩がコード書いて、ダサくない見本を見せてくださいよー。」
あえて甘えた感じでセキヤは言ってみた。
「仕方がないわね。私ならクールにこう書くわ。」
キーボード上に細長く美しい指が流れる光景に、しばしセキヤは見惚れてしまっていた。
「どうかしら。」
サクラの声に我に返ったセキヤ。コードをじっくりと見てみる。
```
var plus = function(a, b)
{
return a + b;
};
var s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
.reduce(plus);
console.log(s);
```
>45
「へ?なんだこれ?」
「クールでダサくないイケてるコードよ。」
「よくわからないですね。とりあえず僕のコードのほうが短くないっすか?」
「今のところはね。」
「あと、ダサいと言われ続ける今の僕のスキルじゃ、先輩のコードは意味がわからないし、ごちゃごちゃしてるようにも見えます。」
「生意気ね。ごちゃごちゃうるさいのはあなたよ。今からそれを説明してあげるんだから、ちょっと黙れ小僧。」
イラッとしたサクラに叱咤されてしまった。
「申し訳ありません、サクラ先輩。大変失礼いたしました!」
セキヤは半ば恍惚としてしまっていた。
###フローは複雑でバグの元凶
サクラはちょっと考えてから作図アプリを立ち上げ、手際よくグラフを作成していった。
![フローチャート画像](https://upload.wikimedia.org/wikipedia/commons/d/d5/Flowchart01.svg)
「セキヤ君、これが何かわかる?」
「もちろんです。**フローチャート**と呼ばれるもので、このフローチャートは僕が書いたコードの流れ、つまり僕のコードのフローをグラフ化したものです。」
サクラは満足そうに頷いた。
「正解。そして今回の問題はなんだったっけ?」
「**『0から9までの数をすべて足すコードを書け』**でした。」
「そうね、では、このフローチャートをぱっと見て、
**これが『0から9までの数をすべて足すコードを書け』の解法を示している**と即座に答えられる人はいったいどの程度いると思う?」
「たしかに、わかりにくいでしょうね。でも少しは居ると思いますよ。」
セキヤの若干の反抗を感じ取り、またちょっとイラついた様子のサクラではあったが会話を続ける。
「いいわ。では仮にこれが『0から9までの数をすべて足すコードを書け』という問題ぽいな!とすぐ見抜けるほど気の利いた人がいるとしましょう。
でもこのフローチャートで表されるコードが、
**本当に『0から9までの数をすべて足すコードを書け』の解法として合っているのかどうか?確信をもって断言できる**人はどのくらい居るのかしら?」
「それは**まず居ない**と言って良いんじゃないでしょうか。**コードにすぐバグが紛れ込む事**はプログラマならば誰でも身を削るようにしてよく理解しているはずです。コードが正確かどうか確信をもって断言できると思ってるプログラマが居るとしたら、そいつはモグリでしょう。」
サクラは再び満足気に頷いた。
「よくわかってるじゃない。つまりセキヤ君のコードはかんたんなようで実は**かなり複雑**なのよ。コードの妥当性を検証するためには、頭の中でフローチャートに従って順番に変数の値を追っかけて何度も確かめてみたり、手っ取り早いのは実際にコンピュータでコードを走らせてみてエラーが出るか試してみる事でしょうね。そのほうが速くて正確。でも、エラーが出ないバグが一番やっかいね。だから最終的には変数をウォッチするデバッグ機能なども利用して変数の値を逐次検証していく必要はある。」
「おっしゃるとおり、**コードのフローを逐一追跡しながら隠れたバグを探し出すのはものすごい骨の折れる作業**ですよね。よくわかります。」
「そして、**これこそが多くのコードが抱える根本的な問題**なの。**バグを解決できずにプロジェクトそのものが頓挫することはままある**わね。セキヤ君のコードがダサいと言われる理由もそこなの。**フローは複雑でバグの元凶なのよ。**」
###フローは不要
「先輩の言うことはもちろんよくわかるんです。でもプログラミングって元々そういうものなんじゃないんですか?フローがあってこそのコードですよね?」
「だから、その発想がダサいのよ。」
うんざりとした調子でサクラが言う。
「そうなのかな?」
「**『0から9までの数をすべて足す』**という問題には、繰り返しや条件判断といったフローはある?」
「**『0から9までの数をすべて足す』という問題自体には、繰り返しや条件判断といったフローはまったく確認できない**ですね。」
「では何故、セキヤ君のコードにはそんな複雑なフローの存在が確認できるのかしら?」
「それしか方法がないからですよ。この問題を解くには、繰り返しや条件判断といったフローを含むコードを書くしかない。フローは絶対に避けられないと思います。」
「ほんとうにそう?私のクールなコードはどうかしら?」
```
var plus = function(a, b)
{
return a + b;
};
var s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
.reduce(plus);
console.log(s);
```
「うーん、言われてみればフローが消えてるなあ。僕のコードにあった**forループの繰り返しや条件判断がすべて綺麗さっぱり消えてなくなっています。**」
「少しは成長したわね。」
サクラはまた満足気だ。
「いい?フローをもってコードを書くことは唯一の方法ではないの。むしろ**フローを書くことは複雑な仕事でバグの温床となるダサいやり方なので、フローは極力さけるべき**なの。」
「なるほど。」
「**『0から9までの数をすべて足す』**という問題にフローはない。ならば、コードもそのままフローなしに書ければいいと思わない?」
「それが出来るならば言うこと無いです。コードはクールになりますね。」
「クールなコードでは、**フローの設計やフローの妥当性の検証に労力を費やすようなダサい真似はしない**のよ。」
「つまり、**プログラミングの最大の課題であるデバッグの手間が激減する**わけですか?それはかなりクールなことになってしまう。」
「わかってきたわね。」
「**フローじゃなくて不要(フヨー)ですね。**」
「ダサいダジャレだけど、まさにそのとおりよ。」
口元をゆるませながらサクラは続ける。
「でもフローが不要という引き算だけでは、私のコードの真価を理解しているとはとても言えないわね。」
「というと?どういうことでしょうか?」
 
###フローを書かず論理をそのままコードに書き写せ
「フローがない、**フローの設計が必要ないということは、問題の論理だけに集中している**、ってことに他ならないの。ここ重要。セキヤ君は、プログラミングで**後々どうせ膨大な検証が必要となるフローの設計**に時間を費やしたいかしら?それとも**問題の論理だけに時間を費やしたい**かしら?」
「それはもちろん、問題の論理そのものだけに集中してコードを書いていきたいです。」
「そうでしょう。私のコードのクールさの真価はそこにあるの。問題の論理そのものに集中しているの。」
「もう少し説明をお願いします。」
「いいかしら?**『0から9までの数をすべて足す』**という問題について、私のクールなコードでは、
```
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] //0から9までの数
.reduce(plus);
//をすべて 足す
```
と、**問題の論理そのものを単純にコードへ、まる写しにしているだけ**なの。」
「あ!?なんで?凄い・・・先輩、やっと見えてきました!」
「わかった?私のクールなコードでキモとなる部分はたったこれだけ。**問題の論理そのものを書き写しただけなんだから、バグが介入する余地なんて最初からどこにもあるはずがない**でしょ?」
「まったくないです。」
「ということは、つまり、私は**本当に『0から9までの数をすべて足すコードを書け』の解法として合っていると確信をもって断言できる**わけ。
プログラミングの世界で、**論理のみで構成された、これ以上望めないほど見透しの良いクールなコードを書くことは、ダサいコードを平気で書く常人プログラマーの想像を超えた『コードを見透せる眼』をもつことに等しい**のよ。」
###『神の眼』のスキル レベル0
![All-Seeing Eye of God画像](http://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Dollarnote_siegel_hq.jpg/300px-Dollarnote_siegel_hq.jpg)
米1ドル札の『すべてを見透す神の全能の目』
(All-Seeing Eye of God)
このサクラの発言で、セキヤには少し思いあたる節があった。
「先輩、それはひょっとして**『神の眼』**のことでしょうか?部員がサクラ先輩は『神の眼』のスキルを持っているとかなんとか噂しているのを聞きました。」
「あー、さあどうかしら?」
「これは『神の眼』のスキルなのですか?」
「なんとも言えないわね。」
「先輩、教えてください。噂の真相を知りたいです。」
「しつこいわね。まだレベルが低すぎるのよ。『神の眼』と呼ぶなら、**これはまだレベル0のスキル**だから。」
面倒になったのか、あきらめるようにサクラは答えた。
「やはり『神の眼』のスキルは本当に存在するんですね!」
「私自身は、単に『見透しの良いクールなコード』とか『コードを見透せる眼』、と普段言っているわ。それを彼らが大げさに誇張しているだけなんじゃないかしら?
だいたい『神の眼』と騒ぐようなたいしたことでもないの。」
「きっと先輩はIQ145あるからそう思うんですよ。部内では先輩のコーディングのスピードとコードにバグが出ないことは有名だし、僕らにしたら先輩が『神の眼』を持ってるとしか思えないんです。」
「そう呼びたければ『神の眼』でもなんでも好きにすればいいわ。」
まったく興味がなさそうに答えるサクラ。 
「先輩、僕は先輩のように『神の眼』のスキルが欲しいです。今の僕はまるでダメですね。これまで、問題の論理を上手にフローに変換してフローを設計する作業こそがプログラミングだと勘違いしていたようです。ダサい己のダサさを認めざるを得ません。」
セキヤはここぞとばかりに自分の熱心さを懸命にアピールしてみた。
「そうね、その自覚がもてればようやくスタート地点に立てたということ。おめでとうセキヤ君、今あなたは、レベル0よ。」
「ありがとうございます。『神の眼』のレベルがあがるように頑張ります!」
###『神の眼』を得るための唯一の方法
「まったくしょうがないわね。
とにかく今後『神の眼』のレベルを上げていきたいのであれば、
**問題の論理そのものをコードに単純に書き写すことを徹底的にやっていく**ということを常に肝に銘じて置いて頂戴。**これがクールなコードを書くための唯一の方法**よ。」
「了解しました。」
「もういちど私のクールなコードでキモの部分を確認するわよ。
```
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] //0から9までの数
.reduce(plus);
//をすべて 足す
```
**問題の論理そのものをコードに単純に書き写すことを徹底的にやっていく**の。
まず「0から9までの数」という論理があるならば、フローでごちゃごちゃやることなど考えないで、単純に`[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]`と**そのままのデータまるごと用意してしまう**の。」
「わかります。」
「次に、その用意されたデータへ、**『をすべて足す』**という論理操作をしてやるのね。」
「 `.reduce(plus); //をすべて足す`
という部分ですね。」
「これを合わせると、**『0から9までの数をすべて足す』**という論理をコードに書き写したことになるの。ひたすら**問題の論理そのものをコードに単純に書き写すことを徹底的にやっていく**わけ。わかる?」
###関数 ・function という論理操作
「 先輩、
```
.reduce(plus); //をすべて足す
```
ここなんですが、reduceとplusも2つともJavaScriptでいう**関数**ですよね?」
「そうね、関数について説明しておいたほうがいいわね。」
「僕はざっくりとしか理解してないので、おねがいします。」
「**関数**というのは中学校の数学の授業でも習うとおり、もともとは数学用語なの。それがそのままプログラミング用語に転用されたものね。
**数学・プログラミング用語として、英語ではfunction、それを和訳したものが関数**なの。ぶっちゃけ、関数というのはfunctionの翻訳語としてはさほど気の利いたものだとは思えないわね。
そもそもの**functionとは、機能、動作、操作、作用、という意味**。
だから**関数=function=機能、動作、操作、作用とざっくりイメージしておいて**頂戴。」
サクラは、また作図アプリで手早く何か描き始めた。
![関数イメージ画像](http://upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Function_machine2.svg/485px-Function_machine2.svg.png)
「だいたいこういう感じのイメージよ。
**INPUT(インプット)とOUTPUT(アウトプット)**というのはわかるわよね?」
「半ば日本語にもなっているので、それはよくわかります。**インプット=入力があってアウトプット=出力がある**、というやつですね。」
「`f`という名前のFUNCTIONがあるの。これに`x`をINPUT(入力)してやると、`f`が持ち合わせる機能によって作用され変化したOUTPUT(出力)が出てくるわ。
このOUTPUT(出力)は、**`f`で作用して変化したという印(しるし)として`f(x)`と書き表す習わし**になっているわね。
`x`
↓`f`
`f(x)`
ということ。」
「工場にあるマシンみたいなものですね。」
「まあ、工場に限らないわよ。家庭にある
**炊飯器、電子レンジみたいなマシンもFUNCTION・関数**なの。
`炊飯器`という名前のFUNCTIONがあるわね。
これに`米と水`をINPUT(入力)してやると、
`炊飯器`が持ち合わせる機能によって作用され変化した
`炊きたてのご飯`というOUTPUT(出力)が出てくるわ。
`x`
↓`f`
`f(x)`
という表記でやると、
`米と水`
↓`炊飯器`
`炊飯器(米と水)`
ちょうどこうなるわよね。」
「あ!`炊飯器(米と水)`というのはちょうど
`炊飯器`というマシンの( 中 )に`米と水`がゴッソリと投入された図式になっていますね!」
「そうね、イメージできたかしら?
そしてこの`炊飯器`というマシンOUTPUT(出力)である
`炊飯器(米と水)`とは`炊きたてのご飯`なので、
`炊きたてのご飯 = 炊飯器(米と水)`
という論理操作の関係、論理構造になっているわね。」
「関数・functionの意味を100%理解しました。」
「そうね、でももうちょっとガツンとくるイメージはないかしら?
ああそうだ、セキヤ君は**『大改造!!劇的ビフォーアフター』**という庶民のための娯楽番組は知ってるかしら?」
育ちの良いサクラによる「庶民」という言葉遣いが少々気になったもののセキヤは答える。
「もちろん知ってますよ!
**『様々な問題を抱えた家』**があって、超能力者みたいな**『匠』**がなんかやったら、家が**『大変身』**しちゃう国民的オカルトドラマです。
**Before(ビフォー)とAfter(アフター)の凄まじい変化**を見たサザエさんの声の人が**『なんということでしょう!!』**って感激して、家族も感激して、その家庭には恒久的平和が訪れます。」
「まったくそのとおりよ。
**INPUT(インプット)とOUTPUT(アウトプット)**というのはこの際、**Before(ビフォー)とAfter(アフター)**とセキヤ君の脳内で変換してもらっても別に構わないわよ。」
「わかりました。」
「**Before(ビフォー)の『様々な問題を抱えた家』は**
**『匠』の手が加わると**
**After(アフター)の『なんということでしょう!!』**
に『大変身』するの。
**(Before)『様々な問題を抱えた家』** 
**↓『匠』**
**(After)『なんということでしょう!!』**
**『匠』はFUNCTION・関数**よ。
だから、**『匠』**に
**『様々な問題を抱えた家』**というBefore、言い換えると、
『様々な問題がある家』をINPUT(入力)して
匠にその問題を『抱えさせて』やると、
**匠(様々な問題を抱えた家)**となり、
その『大変身』したAfterは**『なんということでしょう!!』**なので、
**なんということでしょう!! = 匠(様々な問題を抱えた家)**
という論理操作の関係、論理構造になっているわね。」
「なるほど先輩、
**匠(様々な問題を抱えた家)**というイメージもピンときました。
『様々な問題を抱えた家』の『様々な問題』を番組進行上、
抱え込む当の人物は、家族でも番組スタッフでもサザエさんの声の人でもなく、『匠』その人なわけで、
『匠』が『様々な問題を抱えた家』を抱え込むんですね!だから、
**匠(様々な問題を抱えた家)**となる。」
「そうね。あと念の為だけど、『なんてことでしょう!!』というのは、『大変身したリフォーム後の家』のことで、ただ単にそう書くとツマラナイから象徴的に『なんてことでしょう!!』と言い表しているだけだからね?」
「先輩よくわかっています。」
「こんなのイチイチ説明させないでよ?」
「すみませんでした。」
わけもわからずセキヤは謝る。
「あと、この
`炊飯器(米と水)`の()の中に入る
`炊飯器`関数に投入した`米と水`のこと、
そして、
**匠(様々な問題を抱えた家)**の()の中の
『匠』関数に投入した『様々な問題を抱えた家』のことは、
**引数(ひきすう、いんすう、argument、Parameter)**
と呼ばれているので一応覚えておいて。」
「わかりました。そして
**『関数・functionというものは、作用して変化させる、という論理操作』**であることもよくわかりました。」
###関数は論理の最小単位の部品として最上の扱いを受ける
「先輩、
```
.reduce(plus); //をすべて足す
```
で、 `reduce`と`plus`という2つの関数が組あわされて『//をすべて足す』という関数になってしまっているのでしょうか?」
「まさにそのとおりよ。
『//をすべてxx』と『足す』という2つの関数が組み合わさっているの。」
「2つ関数が組み合わさって、『//をすべて足す』という関数になるんですね。」
「**問題の論理そのものをコードに単純に書き写すことを徹底的にやっていく**ためには、あらゆるものがレゴブロックのように組み合わされることが超重要。
**関数は、レゴブロックのような最小単位の部品なのよ。論理の最小単位としての部品。**」
「先輩のコードをよく調べてみると、
```
.reduce(plus); //をすべて足す
```
のうち`plus`という関数は、
```
var plus = function(a, b)
{
return a + b;
};
```
という形で『足す』という論理の最小単位で部品として独立しているんですね。」
「そうね。セキヤ君、いいところに気がついたじゃない。
`米と水`
↓`炊飯器`
`炊飯器(米と水)`
の表記に対応させてやれば、ちょうど
`a, b`
↓`function`
`function(a, b)`
という形式になっているわね。
このコードのしょっぱなの
`var`
というのは、定義するというコマンド(実行環境・コンパイラへの命令)よ。
`var plus =`
ということは今から`plus`を定義する、というコマンドになるの。
`plus`という変数とは、
**これこれこういう『足す』という論理操作**の関数である!!
と定義してやってるのよ。
もうちょっと日本語でひらたく言えば、
**これこれこういう『足す』という論理操作**の関数
には`plus`って名前をつけてやりますよ、ってこと。」
「なるほど。先輩、**『これこれこういう』**っていうのは、
```
{
return a + b;
}
```
の部分ですね?」
「もちろんそうよ。
 この`{}` 中括弧の中でその関数の論理操作、機能の説明、つまり論理の設計をしてやるコードを書くわけ。
 
`炊飯器`の機能をクドクドとここで説明して、いかにして`炊きたてのご飯`を出力するだけの能力がある`炊飯器`に仕上げるのか?きっちり設計するのよ。
**『匠』**ならば、**『なんということでしょう!』というAfterの感動**をもたらす**『匠』の超能力**の秘密をこの部分でクドクドとバラして、『匠』のリフォームスキルを徹底的に設計してやるの。」
「今回の
**これこれこういう『足す』という論理操作**
という具体例でいえば、
```
return a + b;
```
という設計となっていますね?」
「そうね、
`return` っていうのもコマンドで、和訳すると「返す」みたいな意味。
`a`と`b`を足した値を返せ、と命令しているの。
つまり、この関数では、
- OUTPUTとして、`a`と`b`を足した値を返せ、
- `a`と`b`を足した値をOUTPUTとして出力せよ、
- `a`と`b`を足すという操作をしろ、
まあどれでもいいわ。全部同じ意味。単に言葉の問題にすぎないわ。」
「よくわかります。」
「じゃあ、全力でまとめるわよ?
`米と水`
↓`炊飯器`
`炊飯器(米と水)`
の表記に対応させてやれば、ちょうど
`a, b`
↓`function`
`function(a, b)`
で、`var plus = function(a, b)`
とこのfunctionには、
`炊飯器`という名前と同じように、
`plus`という名前をつけてやったので、
`a, b`
↓`plus`
`plus(a, b)`
という流れになっているわね?」
「はいわかります。」
「そして、この`plus`というfunctionの実体とは、
`a + b`という論理操作であると、
`{}` 中括弧の中で具体的にクドクドと説明されて、設計されている。」
「はい、``` return a + b; ```というコマンドで、『`a`と`b`を足すという操作をしろ』と設計されていました。」
「そうね、これくらいでいいかしら?」
「先輩、`炊きたてのご飯`や『なんということでしょう!』に対応するのは何ですか?」
「だから、それは`a+b`という具体的な計算結果というOUTPUT、計算のAfterの値じゃない。」
「ああそうか、なるほど。」
「こうなるわね。
`米と水`
↓`炊飯器`
`炊きたてのご飯` = `炊飯器(米と水)`
**様々な問題を抱えた家** 
**↓匠**
**なんということでしょう!! = 匠(様々な問題を抱えた家)**
`a, b`
↓`plus`
`a + b` = `plus(a, b)`
よろしいかしら?」
「よろしいです。」
「こうやって論理の最小単位をクドクドと説明して、きっちりと設計してやるの。そうやって仕上がった関数は、レゴブロックのように自由自在に取り回せるし、レゴブロックのように自由自在に組み合わせることができるわ。
こういう部品は、
**第一級オブジェクト(first-class object)**ってクールに呼ばれているわね。」
「というと、JavaScriptの関数はファーストクラスのオブジェクトですか?クールですね。」
「ええ、JavaScriptの関数はゴリゴリのファーストクラスよ。**ファーストクラスな部品である関数は、ファーストクラスなので第一級、最上級のクールな扱いを受ける**わ。
**『足す』という論理操作は、それ自体が最小単位として独立しており、きちんとファーストクラスの最上級の扱いを受ける資格がある**のよ。」
「先輩、関数が論理の最小単位の部品、っていうことは、さっきの関数としての`炊飯器`や『匠』も最小単位の部品として最上の扱いを受けるってことですね?」
「もちろんそうよ。`炊飯器`や『匠』はファーストクラスで最上の扱いを受けるわ。
ご飯がなくなったら炊飯器さえあれば、また炊けるじゃない。匠がいないと番組は成立しないわ。論理操作としての関数こそが重要なの。」
「よくわかりました。そういえば、CとかC++とかJavaとか、確か関数はこんな論理操作の部品となる特権など与えられていなかった気がします。」
「与えられていないわね。だからJavaScriptとは違ってこういうクールなやり方をするのはかなり難しくなるわ。」
「関数がファーストクラスかどうか?っていうのはプログラミングではかなり重要なスペックなんですね。今後プログラミング言語を調べるときには注意してみます。」
「**FUNCTION・関数は論理の最小単位の部品で最上の扱いを受ける。ここはクールなコードにとって重要**なところよ。」
###問題の論理には結果など含まれていない
「先輩、`炊飯器`や『匠』はファーストクラスで最上の扱いを受ける価値があることはわかりました。
では、『炊きたてのご飯』や『なんということでしょう!』はどうなんですか?」
「それらもファーストクラスの部品であり、もちろん自由に取りまわせるけど、クールなコーディングでは価値はないわね。」
「『炊きたてのご飯』や『なんということでしょう!』は重要ではないってことですか?」
「まったく重要ではないわ。」
「何故ですか?」
「それらは『OUTPUT』であり『After』であり『結果』にすぎないからよ。」
「でも、OUTPUTとか結果は重要なんじゃないかな・・・」
イラッとしたサクラはセキヤをキッと睨みつけながら言う。
「セキヤ君、あなたまだ何にもわかっていないのね!」
「す、すみません。」
「もういちど問題!」
「はい?」
「最初に出した問題よ。」
サクラはぶっきらぼうに言う。
「あ、『0から9までの数をすべて足すコードを書け』でした。」
慌てて答えるセキヤ。
「で、クールなコードを書く方針は?」
「えー、**『フローは不要。問題の論理をそのままコードに書き写せ。』**でした。」
「そうね。じゃあ、問題に結果は含まれているかしら?」
「え?」
「あなたは、OUTPUTという結果は重要だと思うのでしょう?
で、『0から9までの数をすべて足すコードを書け』という問題の論理には結果なんてものが含まれているのかしら?」
「あ!問題の論理に、結果が含まれていることなどは絶対にありえません。問題に結果(答え)が書かれてるならば、もはやそれは問題でもなんでもない単なる答えになってしまいます。」
「問題の論理にはけして存在しえないAfterの結果を重要視することは、問題の論理をそのままコードに書き写すことに繋がるのかしら?」
「いえ、完全に間違った方向性ですね。」
「ではあなたは何故そんなダサい考え方をするの?」
「よくわかりません。無意識についそう考えてしまっていました。どうもすみませんでした。」
セキヤをなじることに飽きたのか、サクラは少し調子をゆるめた。
「いい?セキヤ君。これはダサいプログラマーの悪い癖なのよ。
『フローは不要』なのに、フローを書く癖が抜けないのね。」
「結果を重視する癖が、フローを書く癖と関係あるんですか?」
「大有りよ。あなたのダサいコードのフローチャート
![フローチャート画像](https://upload.wikimedia.org/wikipedia/commons/d/d5/Flowchart01.svg)
を見てみましょう。
`s+n →(結果)s`
であるとか
`n+1 →(結果)n`
であるとか、とにかくいたるところで『結果』を計算しているの。そして次のループでその『結果』を利用してまた次の『結果』を計算していて、その次も・・・というループを10回繰り返すわけよね?」
「あーおっしゃるとおりです。先輩。」
「つまり、あなたのダサいコードは、**問題の論理にはありもしない『結果』を何度も何度も計算させながらループを回すというフローとして設計されている**の。
念の為だけど、私のクールなやり方でも実行環境は私が感知しない、する必要もない裏で計算しているし、実行効率の問題を言ってるんじゃないわよ。コードの書き方としてダサいと言ってるの。」
「もちろんわかります。」
「こういう、問題の論理とは一切関係もなく、フローの中で何度も計算されて刻々と値が変化して、フローの制御に組み込まれてしまっている`s`とか`n`みたいな変数のことを**状態変数**と呼ぶの。
こんな、問題の論理とはまるで関係ない分際で、刻々と変化するような状態変数なんてものはなくしてしまいなさい。論理を設計する上で邪魔だわ。
**フローがバグの元凶であるのと同様に、状態変数もバグの元凶**よ。」
「たしかに、フローがあれば状態変数も必ずありますね。」
###手順を分割するな、論理を分割せよ
「こういう結果を小出しにしながらフローを回すのは何故か?というと、ダサいプログラマーは**手順を分割しようとしている**からよ。」
「というと、どういうことでしょうか?」
「『様々な問題を抱えた家』があるわよね?
①匠に玄関を直させる
⇒結果(プチAfter)『なんということでしょう』。
②匠に台所を直させる
⇒結果(プチAfter)『なんということでしょう』。
③匠に階段を直させる
⇒結果(プチAfter)『なんということでしょう』。
・・・
このように、**手順を分割して逐一結果を小出しにしながら実行するのをプログラミングだと思いこんでいる**のね。だいたいこんな小出し小出しにAfterを見せられる番組なんて面白くもなんとも無いわ!」
サクラは解説しながら、またイライラしはじめたらしい。
「確かに、自分のこと考えればしっくりと来ます。というか、これ以外の考え方なんてしたことがありませんでした。僕はダサくて愚かです。」
サクラのイラツキを察したセキヤは殊更に反省した素振りを従順にアピールする。
「そうでしょうね。それに対してクールなプログラマーは**論理を分割しようとしている**の。もう何度も言ってるわよね?論理の最小単位である関数という論理操作を自在に組み合わせながら論理を設計していくって。」
「はい。言っておられます。」
「『様々な問題を抱えた家』があるわよね?
『玄関の専門的スキルをもつ匠』を設計する。
『台所の専門的スキルをもつ匠』を設計する。
『階段の専門的スキルをもつ匠』を設計する。
それぞれの匠を論理的に自在に組み上げて、最終的に『たったひとりの匠』に仕上げる。
この彼こそが『様々な問題を抱えた家』の『様々な問題』を一挙に解決する能力をもつ『万能のスーパー匠』なのよ。
ここまですべて論理操作の構成しかやっていないの。
**問題の論理そのものをコードに単純に書き写すことを徹底的にやっていく**わけ。
そして、**『万能のスーパー匠』を組み上げることこそが問題の論理であり、それはそのまま問題の解決になる**の。
途中の過程で逐一命令する必要など皆無なのよ。
**『万能のスーパー匠』はすべてやり方を知っており、その行動についてこちらはいちいち口出しない。**
最後の最後に結果を一度だけみると、その**Before(ビフォー)とAfter(アフター)の凄まじい変化**を見たサザエさんの声の人が**『なんということでしょう!!』**って感激するのよ。」
「家族も感激して、その家庭には恒久的平和が訪れます。」
「それをやっているのが私のクールなコードなのよ。見なさい。
```
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] //0から9までの数
.reduce(plus);
//をすべて 足す
```
`reduce`と`plus`という2つの関数が組あわされて『//をすべて足す』という関数になっているわね?
**この2つの関数が、『匠』よ。**
これは、**それぞれ逐一実行しろ、という計算の手順書ではない**わ。
**2つの関数を組み合わせて、**
『//をすべて足す』といういう**『スーパー匠』を設計**してやっているのよ。」 
「**論理操作の組み合わせの設計だけで、Afterという結果や、途中の計算手順も、フローも、変化し続ける状態変数も何ひとつない**んですね。」
「そう。**手続きを分割して結果を小出しにするループのフローを書くのではなく、論理を分割し論理だけを構成しなさい。**いいわね?」
「はい。よくわかりました。」
###『まとまり』は美しい単一の論理構造
 
「セキヤ君、いい?
`[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] //0から9までの数`
というのは『まとまり』なの。
**『まとまり』というのは、まとまっているのだから極めて単純で美しい論理構造**なの。
**『まとまり』という単一の論理構造はこれ以上分割する余地はない**。
しかし、**こういうせっかくの単一の『まとまり』という論理構造を、わざわざバラバラにしてしまって、手順を分割して、結果を小出し小出しに計算していくのがあなたのダサいコードなのね。繰り返し処理っていうのはそういうこと**。
論理構造を無視し、手順に溺れる、
それがダサい繰り返し処理というフローなのね。**フローは不要。**」
 
「**『まとまり』は美しい単一の論理構造**、ですね。わかりました。」 
###『まとまり』をまるごと処理ができる関数
「この『まとまり』をまるごと処理ができる関数が、実は
`.reduce(plus); //をすべて足す` の`.reduce`なの。
セキヤ君、これを見て気がついたことを言ってみて。」
「同じ関数でも`.`(ドット)が頭についていますね。それから`plus`を引数として取り入れているようです。」
「はい、まず`.`(ドット)が頭についていることについて説明してあげるわ。」
「お願いします。」
「そもそも、この`.`(ドット)は、
```
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] //0から9までの数
.reduce(plus); //をすべて足す
```
というように、`[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]`という配列に紐付けられているわけね。
JavaScriptの配列には、`reduce`というファーストクラスな関数が、
最初から装備されているということなの。
つまり、この`reduce`はJavaScriptの配列お抱えの論理操作の最小単位なのよ。配列はぜひ、この論理で操作してください、と周到に前もって準備がなされているのね。」
「先輩、なぜそのような周到な準備がなされているのでしょうか?」
「なぜなら、配列というものが『まとまり』だからよ。
**配列という『まとまり』をまるごと処理ができる関数が用意周到に準備されて提供されている**の。
実際、`[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]`というのは、
**問題の論理そのものをコードに単純に書き写すことを徹底的にやっていく**
というクールなポリシーに従って、
**そのままのデータまるごと用意してしまった**わけね。
こういうクールなやり方では、
**配列という『まとまり』をまるごと処理ができる関数**は必要不可欠になるのよ。」
「**『まとまり』は美しい単一の論理構造**、
それをまるごとそのまま処理できてしまう関数が必要不可欠。」
「そういうこと。他に気がついたところはある?」
「あと、`plus`は普通に『足す』とわかったんですが、
`reduce`という言葉の意味が不明です。普通に訳せば**減らす**ですよね?」
「ああこれは、むしろ数学用語なの。**通分する、約する、方程式を解く**という意味で使われるわ。
今回のケースでは、
`[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] //0から9までの数`
をすべて足すと`45`というように、10個のデータが計算されてひとつに集約されるじゃない。だいたいそういう操作のイメージよ。」
「なるほど、そう言われてみると合点がいきますね。」
###他の関数を取り扱う能力をもつ関数
「次に、 `.reduce(plus); //をすべて足す`
というように、`plus`を引数として取り入れていることについて説明。
さっきみてきた通り、`plus`という関数は『足す』という論理の操作で、ファーストクラスの最上級の扱いだったわよね?」
「はい、論理の最小単位として自由に取り回せます。」
「`reduce`は、配列という『まとまり』をまるごと操作できる関数だけど、
同時に**こういう他の、`plus`みたいな別の関数を取り扱う能力をもった特別な関数**なのよ。」
「なるほど。だから組み合わせができたんですね。」
「こういう他の関数の取り扱う能力を備えた関数のことを特に**高階関数(higher-order function)**と呼ぶわ。ほんとは名前なんてどうでもいいのだけど、他の人たちもそう呼ぶので、話を合わせるために一応知っておいたほうがいいわね。」
「JavaScriptのreduceは高階関数である、と言われても今後凹むことはなさそうです。役立ちます。」
「プログラミング言語って世界共通語といえるけど、高階関数っていう名前は日本語ローカルだからどうせ外国では意味が通じないの。だからといってhigher-order functionって覚えたら今度は日本国内では通じにくいし所詮その程度のものよ。」
「こういう専門用語は日本語・英語どっちで揃えるかややこしいですね。」
###高階関数の柔軟性
「でも、高階関数の存在価値って何?こんなものが世の中に存在している価値ってあるのかしら?」
「もちろんです、先輩。専門的匠の集団から万能のスーパー匠を組み上げる際などには必要不可欠だと思われます。」
「まったくそのとおりね。今回のかんたんな問題でもっと具体的に論じるとどうなるかしら?」
「今回の場合で言うなら、`reduce`は、**『//をすべてXXする』**という、まとまりへの操作として事前準備されているんですよね?
XXというのは、この高階関数が引き受ける別の関数に応じて変化して、**今回は『足す』だったので、組み合わせで、『//をすべて足す』でに仕上がっていた**はず!」
「だから、どういう存在価値?」
「**まとまりへの操作っていうのは、いろんなパターンがありえます。だからそのやりたい操作に応じて柔軟に関数を渡せばいい**んじゃないでしょうか?」
「セキヤ君もなかなかやるじゃない。じゃあ『すべて足す』のではなく『すべて掛ける』場合はどうすればいいのかしら?」
「**『足す』能力を備えた匠を、今度は『掛ける』能力を備えた匠に入れ替えたらいいんです。**だから、**『掛ける』能力を備える匠をまず設計してやれば良い**と思います。」
「では見せて頂戴。」
「多分、余裕です!」
セキヤは意気込んでタイプしはじめた。
```
var multiply = function(a, b)
{
return a * b;
};
var s = [1, 2, 3, 4]
.reduce(multiply);
console.log(s);
```
>24
「いかがでしょうか?」
「合格。」
###論理の最小単位としての関数のちから
「先輩、こんな風に何でも関数は組み合わせられるのでしょうか?」
「今回、たまたま高階関数というホストの存在があったから組み合わせられたのよ。」
「ああ、そうか。」
「なんでもかんでも関数は組み合わせたら良いはずもなくて、それは個々の関数のスペック、性格によるわ。
たとえば、私自身が設計した`plus`関数だけど、
```
var plus = function(a, b)
{
return a + b;
};
```
見てのとおり、これはそもそも問題の論理部品として必要な、数値を足すという操作を想定して私は書いたの。」
「そうですね。」
「たとえば、今セキヤ君が設計した`multiply`関数だけど、
```
var multiply = function(a, b)
{
return a * b;
};
```
同じように、数値を掛けるという操作を想定して書いたんでしょ?」
「たしかにそのとおりです。」
「私達が書いた関数が引数として引き受けるのは数値を想定していて、他の関数を引き受けることまではまったく想定していない。」
「高階関数は他の関数を引き受けることを想定していますね。」
「`reduce`という配列のお抱え高階関数にしたって、あれは誰かがそういう別の関数を引き受けながら操作を実現する想定で設計して書かれたものなの。」
「一口に関数といっても、それぞれの論理を設計するときに、想定みたいなことが事前にあるんですね。」
「そう。そこまで全部含めて、**問題の論理そのものをコードに単純に書き写すことを徹底的にやっていく**ということなの。」
「もちろん、この`plus`関数だって、論理を設計するときに、別のファーストクラスな関数を引き受けてなんか処理するほうがいいのならば、そのように設計して書くのは十分アリだわ。でも今回は、そういう問題ではなかったので、数値のみを扱う関数と想定してこう書いたわけ。」
「なるほどー。先輩、いろいろ全体像がつながってきました。**問題の論理そのものをコードに単純に書き写すことを徹底的にやっていく**ときには、関数はファーストクラスの部品としてバラバラに取り扱えるし、部品としてのそれぞれの関数も、問題の論理に必要なように想定して設計していくんですね。関数単位のコードってなんか素晴らしいなあ。」
さくらは笑みを浮かべる。
「フローを設計するよりも、よほどクールでしょ。これが論理を設計するということなの。」
「関数という論理の最小単位の部品をもってすれば、**問題の論理そのものをコードに単純に書き写すことを徹底的にやっていく**ことは容易いような感じがしてきました。」
「なんでもできるわ。これは本当にクールな方法なのよ。」
「でも『神の眼』のスキルとしてはまだレベル0なんですよね?」
「レベル0ね。でも今日セキヤ君はいちばん大事なキモの部分を学んだのよ。」
「ありがとうございます。サクラ先輩。」
「あ、ちなみに、この**関数という論理の最小単位で、問題の論理そのものをコードに単純に書き写すことを徹底的にやっていく**クールな方法をいちおう世間では**関数型プログラミング**って呼んでいるみたいだわ。」
「名前なんてどうでもいいけど、他の人たちもそう呼ぶので、知っておけば話が合わせられるし、凹むこともないですね。僕が欲しいのはあくまで『神の眼』のスキルです!」
「まだレベル0だから頑張りなさい。もう今日は遅いからここまでにするわ。」
「サクラ先輩、今日はどうもありがとうございました!」
「はい。早くPCの電源落としなさい。さっさと帰るわよ。」
これから数日間、サクラとこんな濃密な時間が共に過ごせるのだ、そう思うとセキヤは再びこう考えるしか無かった。
この高校に入学できてよかった。コンピュータ部に入部して正解だった。今、この瞬間、僕は青春を謳歌している!セキヤは自分の幸運と幸福を噛み締めていた。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment