プログラミングの基礎

浅井健一「プログラミングの基礎」サイエンス社・Computer Science Library (3)

友人の浅井健一さんがプログラミングに関する教科書を書かれました。もしかするとまだ店頭には出ていないのかもしれませんが、浅井さんから本を送っていただいたので、ここで紹介します。

プログラミングを学ぶことことはプログラミング言語を学んでそれを使いこなすことになります。でも、これが難しい。多くのプログラミングの教科書がプログラミング言語の文法 (grammar) を解説しています。プログラミング言語が文法を用いて設計されているから、これが自然な教え方です。文法を学ぶだけではまだプログラミングはできません。各文法要素に与えられている意味 (semantics) が理解できなければプログラムの動きを予想できないからです。では、文法と意味を教わるだけでプログラミング言語を学ぶことはできるのでしょうか?

大学生のときに読んだ"A Practical Introduction to Denotational Semantics," (Cambridge Computer Science Texts, No 23)この本のイントロに以下の記述があります。

The complete definition of a programming language is divided into syntax, semantics and sometimes also pragmatics. Syntax defines the structure of legal sentences in the language. Semantics gives the meaning of these sentences. Pragmatics covers the use of an implementation of a language and will not be mentioned further.

プログラミング言語は文法と意味論、そして時には語用論*1を与えることによって完全に定義できます。文法は言語の正しい文がもつ構造を与えます。意味論はこれらの文がもつ意味を与えます。語用論は言語処理系の使い方を含みますが、これは本書の扱う範疇にはありません。

これを読んだとき、語用論とは何だろうと悩んだ記憶があります。今では、プログラミング言語の設計者が想定した各文法要素の使い方のことではないかと思っています。

プログラミング言語の仕様書というと、文法と意味論からできています。やはり、学生のときにプログラミング言語 Scheme の言語仕様書(R3RS)のコンパクトさに感動しました。最新の Scheme の仕様書ですら50ページしかありません。

minimalist な考え方からすれば、仕様書はこれでよいのでしょうが、プログラミング言語を学ぶためには、これだけでは辛いです。かつて、ACM Lisp Conference で Paul Graham(コメントにあるように、これはぼくの記憶違いだったようです。shiroさんによれば、Richard Gabirielではないかとのことです。)の講演を聞いたことがあります。彼は著名な Lisp ハッカーで、Yahoo! の電子商店を作り、統計的スパムフィルターを発明したことでも知られています。さらに詩人で、画家という多才な人です。で、彼がベンチャー企業を引退して詩の勉強をしていたときに、プログラミング教育の問題に気づいたというのです。詩の勉強では、古今東西の過去に作成された名品を見、その評論などから勉強します。過去に学ぶことから詩の基礎を身につけるのです。Graham によれば、プログラミング教育もそうあるべきではないかというのです。ずぶの素人にいきなりプログラミングをさせるよりも、「20世紀至高のプログラム100撰」みたいなのをひたすら読むのがよいのではないかというのです。

残念ながら、20世紀至高のプログラム100撰は現実にはなく、あったとしても大きな百科事典のような感じになってしまうでしょう。浅井さんの本は、このような視点から書かれているような気がします。一冊の本でプログラミング作法を凝縮するために、ほとんどの章で「デザインレシピ」というものを提示しています。デザインレシピとは、正しいプログラムを作るための系統的で、正しいアプローチを示し、プログラムをデザインし、作るための指針を与えてくれます。以下は関数定義に対するデザインレシピ(p. 26)からの引用です。

目的 作成する関数が何をするものかを考えます。何を受け取り、何を返すのかを考え、関数の型を決定します。これをもとに関数の出だし、ヘッダを作成します。
関数の動きをより明確かつ具体的にするため、作成する関数に望まれる入力と出力の例を作成します。そして、それを実行可能なテストプログラムにします。
本体 関数の本体を作成します。目的のところでは関数が「何を」するのかを考えましたが、ここではそれを「どうやって」実現するかを考えます。
テスト 確かに望む動作をしているか、上で作ったテストプログラムを使って確認します。望む動作をしていなかったら原因をこのデザインレシピに沿って考え、誤りを正します。

浅井さんが採用しているプログラミング言語Objective Caml です。マイナーなプログラミング言語ですが、単純、強力、かつ高性能なプログラミング言語です。実は、わたしが主に使っているプログラミング言語です。

浅井さんのデザインレシピを見ていてObjective Camlがこの種の本の題材として極めて優れていることを理解しました。上のデザインレシピの流れは、ソフトウェア部品の仕様を検討し、それをヘッダとして形式化し、次にテストケースを作成し、プログラムを作成したら、あらかじめ作っておいたテストケースで確認するという風になっています。浅井さんの本ではこのすべての工程が Objective Caml の基本的な機能を用いて実現されています。つまり、ある基礎的な事項を学ぶためのヘッダやテストケースにより複雑な事項の学習が必要とならない点でこの世界に入り込む障壁が取り払われているのです。

デザインレシピのアイデア自体は、浅井さんの発明ではなく、Mattias FelleisenによるHow to design programs: An introduction to programming and computing で提唱されたようです。12月にあるコンサートで浅井さんに会ったときに、彼から熱狂的にこの本のことを勧められました。オンライン版もあります。

  1. はじめに
  2. 基本的なデータ
  3. 変数の定義
  4. 関数の定義
  5. 条件分岐
  6. さまざまなエラー
  7. 組とパターンマッチ
  8. レコード
  9. リスト
  10. 再帰関数を使ったプログラミング
  11. 自然数再帰
  12. ダイクストラアルゴリズム
  13. 一般化と高階関数
  14. 高階関数を使ったリスト処理
  15. 新しい形の再帰
  16. 情報の蓄積
  17. 再帰的なデータ構造
  18. 例外と例外処理
  19. モジュール
  20. モジュールの開発
  21. 逐次実行
  22. 値の書き換えと参照透明性
  23. 副作用命令を使ったプログラミング
  24. まとめ 〜 プログラミングとは 〜

*1:河野真治さんから、pragmatismは言語処理系の実装依存性ではないかというご指摘をいただきました。たとえば、起動時の引数の扱いとか、扱える最大の自然数の大きさとか、確保可能なセルの最大数のようなもののことでしょうか。そうかもしれません。もしそうであれば、この訳は不適切ですね。