プログラミングを教えている方々へ : 『14歳からのプログラミング』の企画意図
どんな分野でもそうだと思いますが入門書を書くのは難しいことです。中高生ぐらいを対象にした入門書を、という依頼を2年前にいただいてから拙著『14歳からのプログラミング』(以下、本書)ができあがるまで、私も色々と考えることがありました。以下では本書の構成の意図のようなものを書いていきたいと思います。本書の読者に向けて、というよりはプログラミングを教えている人達に向けた説明です。初心者向けの入門書というのは、本来、読者に合わせて様々なものがあるのが理想です。本書にしても、基本的には文章で説明するタイプの本なので(もちろん図も多めに入れたつもりですが)、字を読むのがあまり好きでない人には最適な入門書ではないでしょう。そういった人には別なタイプの本や教材が必要です。本書の構成の意図を説明することで、初心者にプログラミングを教えている人が本を書いたり教材を作ったりするときのヒントになればと思います。
どんな入門書にするか
プログラミングというのは「表現」の技術だと思います。まったく同じアルゴリズムのプログラムであっても、どういう構文やライブラリ関数を使って書くか、色々な表現上の選択肢があります。長い main 関数一つで書くのか、いくつかの関数に分割するのか。for や while をどう組合わせるか。オブジェクトを使うのか、無名関数を使うのか。クラスの設計はどうするか、などなどです。良い表現を選べるようになる。プログラミングを学ぶ面白さの一つはこれだと思います。プログラムは動けばよい、という人にとってはその表現の良し悪しなどどうでもよい事かもしれません。しかし良い表現は保守性の良さや拡張性の良さにつながります。良い表現を選べることは実用上も大切なことです。
本書は入門書ですが、プログラミングとは表現の技術である、ということを紹介するように努めています。この点が抜けていると、プログラミングがなぜ奥深い技術なのか、ちっともわからないと思うからです。プログラミングを学んで何かを作れるようになるのも大切ですが、そこに焦点を当てすぎてしまうと、プログラミングは単なる道具になってしまいます。プログラムは動けば何でも良い、という人をますます生み出してしまいそうです。
単純な命令を数多く並べる
本書ではまず最初に、プログラムとはいくつもの単純な命令(あるいは計算式)を実行する順番に上から並べたもの、と説明します。プログラムは上から順に一行ずつ実行されるものだ、というわけです。うるさいことを言えば、一行の中の部分式にも実行順序がありますが、そこは入門書ですから目をつぶっています。こういう逐次実行の概念は Scratch を使った入門書では強調されるようですが、本書でも最初に強調しています。大学の講義でも、そこを勘違いして後でつまずく学生さんを毎年少なからず見かけます。そのため講義でも逐次実行を最初に強調するように気をつけています。プログラミングを知っている人間からすると、ついつい当たり前のことと思ってしまうのですが。
本書は次に一つ一つは単純な命令であっても、数多く並べると思いもかけない複雑なことができる、という例を出します。一方、多数の命令を並べれば原理的にはどんなことでも実行可能ですが(もちろん計算可能性理論の範囲内ですが)、その数には限界があるということを説明します。人間が自分の頭で考えて正しいと確信をもって並べられる命令の数には限界があるというわけです。人間の能力を過信して(根性があれば)どんな複雑で長いプログラムでも書けるはず、と思っている人は実は世の中に多いのかもしれません。しかしそれによって引き起こされているコンピュータのトラブルも多いと思います。
表現の工夫
人間の能力には限界があります。そこで表現の工夫によって、並べる命令の数を抑える必要があります。つまりプログラムの長さを短くする、あるいは簡潔で読みやすい表現に変える必要がある。そう本書では説明します。そのような表現の工夫を学ぶことが、すなわちプログラミングを学ぶこと。次に本書はそういう視点で繰り返し構文や条件分岐の説明をおこないます。同じ命令の並びが繰り返されているところを繰り返し構文で置き換えれば、プログラムの長さはぐっと短くなります。
同じ命令の並びの繰り返しを発見できれば繰り返し構文に置換できます。しかし現実のプログラムでは、まったく同じ命令の並びが繰り返されることは稀です。ほとんど同じだけれども少しだけ違う、という場合が大半でしょう。そのような場合、いわゆるループ定数(今、繰り返しの何回目かを示す定数)をうまく使うとよいことも示します。
連続する同じ命令の並びなら繰り返し構文に置換できますが、プログラム中の離れたところに同じ命令の並びが現れることもあります。そのようなときに利用できるのが関数、という説明で関数を紹介します。関数の引数もけして理解が容易な概念ではありませんが、繰り返し構文のループ定数からの類推で説明します。つまり、命令の並びがほとんど同じだけれども少し違う場合に、その違いを吸収するために使うのが引数だ、というわけです。
繰り返しと分岐、そして関数がプログラミング言語の主要な制御構文です。本書では、これら三つを説明した後に同じことをするプログラムを六通りの表現で書いてみせます。制御構文の使い方を工夫すると色々な表現ができることを具体的に示すためです。どの表現が一番良いかは本書では特に示していません。それは読者が自分で考えて欲しいところだからです。また、どの表現が最も簡潔か、わかりやすいか、は人によって異なるでしょう。
変数について
プログラミングを教えるときは、最初に「変数」を教えたくなるものです。しかし本書では第8章までかたくなに変数を紹介しません。代わりに「定数」を早い段階から使います。(言語によっては定数のことも変数と呼びますが本書では JavaScript の用語法に沿っています。)現代的なプログラミングでは、副作用をともなう変数はなるべく使わず必要がなければ定数を使う、という考えが多くの人に受け入れられていると思います。本書でも、変数は使った方がプログラムが素直でわかりやすくなる場合に使うもの、という立場で説明しています。簡単な例は累算ですが、本書の中では大域変数を使って現在の「状態」を表す例を紹介しています。
もちろん世の中には変数は一切使わないという流儀もありますが、本書はそこまでの立場は取っていません。変数を使えば素直に書ける場合でも関数などを駆使して変数を使わないというのは少し極端すぎます。
変数を第8章まで使わないもう一つの理由は、変数はやはり難しい概念だと思うからです。変数は値を入れる「箱」である、という説明がしばしば使われますが、数値だけでなく参照も扱うとなると箱は適切な例えとは思えません。
本書では、定数や変数は値についた名前である、という立場で説明しています。値(や式など)に束縛された名前、というわけです。a = b = 7 という式の結果は 7 に a と b の二つの名前がついた、と解釈します。定数だけでmutable な値がない世界であれば、この説明で大きな混乱はないと考えます。変数も、途中で違う値につけ変えられる名前(異なる値に再束縛できる名前)、と考えればよいと思っています。
オブジェクトや配列のような mutable な値がでてくると、「箱」の概念を説明した方が良いのではないかと思うかもしれません。そこは迷うところで、人によってはその方が理解しやすいでしょう。本書では第12章以降にオブジェクトや配列が登場しますが、それらは名前と値の組を束ねたもの、という扱いです。
結局、変数を「箱」と説明するのは C 言語が主流だった時代の名残なように思っています。C 言語の変数は確かに箱と説明したくなるものですから。
フローチャートについて
プログラミングに慣れてくると、正しくインデントされた for 文や if 文なら見るだけでその構造が浮かび上がってくると思います。しかし初心者の人は中々そうはいきません。そういうとき、昔なら(今でも?)フローチャートを合わせて図示するのでしょうが、フローチャートの欠点は for 文や if 文の字面と見た目が大きく異なることです。そこで本書では、Scratch のブロックのような絵を使って、for文や if 文のプログラムを見たら、その構造もそこに重ねて見るように促しています。小さな工夫ですが、読者の理解に役立てばと思います。
まとめ
拙著『14歳からのプログラミング』はプログラミングの面白さは表現を工夫する面白さ、という視点で書いてみました。ですからプログラミング言語の構文を説明するときも、それを使うと表現がどう良くなるか、という視点を忘れないようにしたつもりです。内容的にはさほど奇抜なことはなく、古典的なことを普通に書いているだけではあるのですが、プログラミングを教える方々の何かしらのヒントになれば幸いです。[書き手] 千葉 滋(東京大学大学院教授)