図1 静的型宣言の例<BR>C言語の例を示す。
図1 静的型宣言の例<BR>C言語の例を示す。
[画像のクリックで拡大表示]
図2 Lispのリストとアトム
図2 Lispのリストとアトム
[画像のクリックで拡大表示]
図3 リストとアトムの詳細&lt;BR&gt;nilは「空」を表す特別なアトム。
図3 リストとアトムの詳細<BR>nilは「空」を表す特別なアトム。
[画像のクリックで拡大表示]
図4 Lispのプログラム例&lt;BR&gt;階乗を求めるプログラム。
図4 Lispのプログラム例<BR>階乗を求めるプログラム。
[画像のクリックで拡大表示]

 今回はプログラミング言語の型について学びます。型には静的型と動的型の2種類があります。それぞれの歴史的な背景から始め,利点,欠点について学びます。動的型の新しいプログラミング・スタイルである「Duck Typing」も紹介します。

(ネットワーク応用通信研究所 まつもと ゆきひろ)

 プログラミングの世界では,しばしば「静的」(Static),「動的」(Dynamic)という言葉が使われます。静的とは,「プログラムを実行しなくても,ソース・コードを見るだけで分かること」という意味です。プログラムの静的な部分とは,変数や手続きの名前と型,制御構造の構成などです。

 それに対して動的とは,「プログラムを動かしてみないと分からないこと」という意味になります。プログラムの動的な部分とは変数などの具体的な値,実行時間,使用メモリー量などでしょう。

 プログラムが採用するアルゴリズムと入力値が分かれば,実行してみなくても出力が分かる場合もありますが,現実にはそのような単純なケースはほとんどありません。通常,プログラムというものはそもそも実行してみないと結果が分からないような処理を進めるためのものですから,あらゆるプログラムは程度の差こそあれ動的な性質を持っていることになります。ですから,厳密な話をすると静的と動的の境界線はややあいまいになります。

なぜ型が必要なのか

 プログラムの中で静的,動的な性質を持つものはたくさんありますが,今月は主に型について,静的な型と動的な型について解説します。

 プログラミング言語における「型」とは,データの種別を表します。例えば「整数」や「文字列」は型になります。ハードウエアのレベルで考えると,コンピュータは唯一の型,すなわち2進数だけを取り扱います。CPUを直接操作できるアセンブリ言語では,データの型は整数値だけ*1であって,そのほかのデータはこの整数値の解釈によって表現されます。

 例えば文字列を表現するには,一つひとつの文字に番号を振り,その番号を表す整数の並びを扱います。メモリー中の「位置」(アドレス)も整数で表現します。配列やオブジェクトのような,より高度で複雑なデータについても同じです。

 しかし,これではあまりにも低レベルです。このやり方では,人間が整数だけで表されたすべてのデータの「意味」を覚えておく必要があります。うっかり間違えるとプログラムが全く動かなくなります。

 これではプログラマに対する負担が大きすぎるため,プログラミング言語側が進化しました。世界最初のプログラミング言語と言われているFORTRAN(Formula Translator,式変換機)では,プログラム中の変数や式に型が導入されています。プログラムの中で「この変数に格納されるデータは整数に限る」,「これは浮動小数点数の配列である」などの指定ができるようになりました。これが「静的な型」の始まりです。このような型の指定のことを「型宣言」と呼びます。図1[拡大表示]に静的型の言語の代表として,Cの型宣言を示しました。

 整数型であると指定された変数に,あるプログラムが文字列データを代入するとします。プログラム中の指定によってコンパイラは,代入元の型(文字列)と代入先の型(整数)を「知っている」ため,不整合があった場合,検出できるのです。静的な型は,プログラムを実行しなくても人間の間違いを機械的に発見できる偉大な発明となりました。

動的な型はLispから生まれた

 FORTRANの数年後に登場したLisp(List Processor,リスト処理機)では,型問題に対して異なる解決策を導入しました。1958年に登場した当初はLispはわずか2つのデータ型,「リスト」と「アトム」しか扱えませんでした。

 リストとは2個のノード(要素)を持つ単純な連結リストです。例えば「(5 13)」のようなものです。アトムとはちょっと説明が難しくなりますが,一言で言うと「リストではないもの」です。例えば数値や文字列はアトムです(図2[拡大表示])。

 リストの個々のノード(歴史的にconsセルと呼ぶ)はそれぞれ他のconsセルまたはアトムを指すことができます。consセルは2つの参照先を持つことができますが,歴史的な理由から最初のものをcar(カー),後のものをcdr(クダー)と呼びます(図3[拡大表示])。

 Lispにおいてもプログラムやデータを文字で表現できないと扱いが面倒です。そのため「S式」と呼ばれるリストの文字列表現を採用しました。S式は以下のようなルールでリストを文字列化します。

●consセルは,carの値とcdrの値をドットでつないでかっこでくくったもので表現する

●cdrがリストであればかっこを省略する

●末尾のcdrがnilであれば「. nil」を省略する

これらのルールを順に適用すると,図3のリストは次のように表現できます。先頭に示したものから順に簡略化して3行目に至ります。

(1 . (2 . nil))
(1 2 . nil)
(1 2)

 Lispはデータもリスト,プログラムもリスト,あらゆるものをリストで表現します。LispではS式で表現されたリスト構造自体がプログラムになっているのです。図4[拡大表示]はLispで階乗を求めるプログラムです。

 Lispのリストではそれぞれのconsセルが指している先がconsセルなのかアトムなのか,事前には分かりません。リストはconsセルとアトムが混在した本質的に多形(ポリモーフィック)なデータ構造であると言えます。このようなデータ構造を基本とするLispでは,「データそのものに自身の種別についての情報を記録する」という戦略を採ることになりました。データ自身がデータ種別について「知っている」,このようなデータ型を「動的な型」と呼びます。

 Lispプログラムでアトムだけを対象とする処理をconsセルに適用すると,実行時にチェックが入り,エラーになります。実行時に型チェックを実行するため,不正な処理に進むことはありません。しかしながら,実際に実行してみないとある処理が不正かどうかは検出できません。