Entries

スポンサーサイト
[EDIT]
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

-件のコメント

コメントの投稿

新規
非公開にする

-件のトラックバック

トラックバックURL
http://harukazehajime.blog115.fc2.com/tb.php/126-c4709e0d
この記事に対してトラックバックを送信する(FC2ブログユーザー)
プログラミングとその手法
[EDIT]
プログラミングとは
「プログラムナンバー1番、開会の言葉。校長先生、お願いします」
小学生時代、運動会で読み上げられたこのセリフ。懐かしいものですね。
ことさら運動会では、ことを進める手順が示された紙を手渡され、自分の出番はいつかとか、親御さんなんかも我が子の活躍を残そうとその紙と睨めっこしたりしたかと思います。
運動会を進行するための手順を示された紙を「プログラム」と呼びました。コンピュータにおけるプログラムも、やはり物事を進める手順を書いたものになります。そして、プログラムを作成することを「プログラミング」といいます。走ることを「ランニング」、料理することを「クッキング」というのと同じですね。

コンピュータとして最古のプログラミングは、スイッチや電気配線を手動で切り替えるものと、パンチカードや紙テープ(さん孔テープ)などを用いて、スイッチを自動的に切り替えさせるためのスイッチの状態を示して行っていました。例えば、ある値同士を加算したいときは、加算装置(加算器)に信号を送るように配線を切り替えて(あるいはコンピュータ内部で自動的に切り替えさせて)いたわけです。
後者に該当する全自動コンピュータでは、例えば1+2を計算するにはテープに開いた穴で0(穴なし)と1(穴)の2進数を用い、1と2、そして加算命令を表す番号を作ることでプログラミングしていました。これが一番最初のプログラミング言語、機械語です。
例えば24桁の枠があって、加算命令を最初の5桁で表して、次の3桁で計算結果をどうしたいか――メモリに置いておくとか、画面に表示させるとかプリンタに印刷させるとか――を示して、次の8桁に1、残った8桁に2の穴を開ける、という要領です。仮に「加算してメモリに置いておく」を加算命令を1、出力方法を4として、穴をx、それ以外を_とするとこんな感じでテープやカードにパンチします。
____x x__ _______x ______x_
直前に何が何を意味するかを解説しても、この羅列を見たとたんに頭が混乱するでしょう。また、どこかが間違えていたとき、テープを読み直して意味を把握しつつ間違えを直すには相当な労力が必要です。そこで、先ほどの例であれば加算命令に対してADDという略語(ニーモニック)を当ててやり、略語を用いながらいったん紙にすべてのプログラムを書いて、完成したらすべてのプログラムをニーモニックと2進数(穴の羅列)の対応表とを照らし合わせながらカードに穴を開けていくという方法が考え出されました。アセンブリ言語の誕生です。しかしアセンブリ言語ができても、カードそのものには相変わらず機械語としてパンチされていました。
しかし、対応表から機械語に変換する作業は単純なので、それをコンピュータに担わせるようになります。その作業を担うのがアセンブラと呼ばれるプログラムです。
入力するのは相変わらずパンチカードやさん孔テープですが、穴の組み合わせでソースコードを書き、あとはアセンブラと今の足し算のカードを読み込ませればアセンブラが機械語に直してくれる、ということです。
しかしながら、アセンブリ言語(以下、言語もアセンブラと略)は結局のところ機械の命令を英語による略語にしただけなので、複雑な処理を書くには不向きでした。例えば、(1+2)×(3+4)を計算するには
1をメモリから読み取ってアキュムレータ(累算器:計算の途中結果などを保存しておくメモリ)に入れる
2をメモリから読み取ってアキュムレータに保存された値に直接加算する
アキュムレータからメモリに移動する
3をメモリから読み取ってアキュムレータに入れる
4をメモリから読み取ってアキュムレータの値に加算
1+2の結果を保存した場所から読み取ってアキュムレータの値に乗じる
という、非常に面倒な手順になります。今はアキュムレータに相当するレジスタというものがたくさんあるのでもうちょいスマートなんですが、時代が時代なので。アキュムレータに相当するものすらなかったかもしれませんが...。

なにはともあれこれではさすがに面倒なので、数式を数学通りに書けるようにしたい人もいたわけです。
そこで1952年に、Autocodeなる高級言語が生まれました。
しかし、当時のコンピュータは今のパソコンにすら及ばない時代でしたから、アセンブラか機械語以外は受け入れられず、Autocodeはあまり普及せずに終わりました。とはいえ10年間は使われていたようです。
そのような中、可能な限り性能を引き出すよう機械語を出力する(最適化する)コンパイラとプログラミング言語が1957年に完成します。半世紀以上過ぎた今なお現役のFORTRANです。
当然のごとくその性能に疑いの目が向けられるわけですが、命令の数が大幅に削減できるようにも設計されていて、FORTRANを一気に普及させました。FORTRANは様々なマシンに移植され、より効率的な機械語を出力させようという要求からコンパイラの性能も開発技術も向上していき、コンパイラ型言語の火付け役にもなりました。これ以降、コンピュータとOSの進化、ユーザやプログラマーの要求に合わせて様々なプログラミング言語が開発されることになります。
ちなみにこれら2つの言語はいずれも、アセンブラに一般的な計算式が使えるようになった程度のものだったと言われています。そのうち大成功をおさめたFORTRANは、非常に大きな数値から非常に小さな数値までを扱える浮動小数点数という数値表現方式を持ち、科学計算を中心としたニーズに合わせて進化していきました。この分野は後にスーパーコンピュータへと発展し、FORTRANもスーパーコンピュータに合わせた機能が加わっています。

追記@2011.02.21
プログラミングの歴史を語るうえで欠かせないもう一つの言語に、COBOL(Common Business Oriented Language)があげられます。歴史的に見れば5番目に誕生した高級言語で、FORTRANに次いで2番目に世界標準として仕様が規格化されたこの言語は、もう一つのコンピュータの用途である事務処理のためのプログラミング言語です。
世界初のコンピューターが登場する前にタビュレーティングシステムと呼ばれる自動集計・作表支援機があったことからすれば、事務処理用途としてもコンピュータが使われることは自明でしょう。
こちらはファイルへの入出力を中心としたもので、メインフレーム(コンピュータが登場した当時はコンピュータといえばメインフレームを指しました。現在では様々な用途に合わせたコンピュータが存在するため、メインフレームや大型汎用機などと呼ばれるようになりました)と呼ばれる範疇のコンピュータの特徴であるレコードベースのファイルの扱いに長けています。このファイルは極端に言うと、テキストデータで構成されたデータベースと言うことができるかと思います。たとえば給与明細のような、任意の文字○文字で可変長、3桁ずつ , で区切る数字○桁固定、というような決まりきった形式のデータを表現するのに長けています。
また通貨などは小数点以下まで厳密に扱う必要があるため、プログラム内部でも計算誤差を出さない数値表現が可能になっています。後にJavaなどで多倍長数(任意桁数の整数や小数)演算を行うときに、COBOLでよく使われる数値表現BCD(Binary Coded Decimal、二進化十進数)の一種を利用しています。

一方で、このころ出回ったプログラミング言語はいずれも特定分野に特化されているか性能が悪く、OSを開発するにはアセンブラ一択という状況が続きます。もっとも、当時はほかのCPU向けに移植するという考え自体がなく、同じメーカーでも新しいCPUで従来のOSが動作しなくなった時点でそのCPU向けに作り直す、ということが一般的でした。性能を引き出す以外にも、移植性をほとんど考慮していなかったゆえの選択と言えるでしょう。しかし、FORTRAN以降の高級言語ブームで、手間をかけずに開発したいという思いも高まっていました。

1960年に世界標準として規格が制定されたALGOL(Algorithmic Language)が、まずElliot 503というコンピュータの開発用に拡張を加えて使われ、その拡張版をそのまま利用して1961年からBurroughs(後の汚名高きUNISYS)のコンピュータに用いられました。しかしALGOLにはアセンブラ相当の能力がないと思われることが多く、OSの開発用に使われることはほとんどありませんでした。もっとも、大幅に拡張を施したからこそこれら2つのマシンが生まれたのもまた事実です。
1963年頃に実装されたとされるCPL(Combined Programming Language)はC言語の遠い祖先とされていますが、巨大で複雑だったためコンパイラの開発に時間がかかり、コンパイラが完成した頃には自然消滅しつつあったようです。
1964年にPL/I(Programming Language One)がMulticsの開発に使用され、後に大型機の主力言語のひとつとして今日まで利用され続けています。これのマイクロプロセッサ向けであるPL/Mが開発され、CP/Mの開発にも用いられました。
1966年にはC言語の祖先のひとつとなるBCPL(Basic-CPL)がMultics上で開発されています。CPLを簡素化したもので、これはTRIPOS(1976年)、AmigaOS(1985年)、そしてGUIを使用したパソコンの第一歩であるAlto(1973年)などに使われています。完成間もない頃のBCPLはMulticsのみコンパイラ言語として実装されましたが、コンピュータの性能向上に伴ってほかのコンピュータ向けにもコンパイル可能な言語になりました。現在は開発したマーティン・リチャーズの元でオープンソースで配布されています。
Multicsに挫折したメンバーのうちUnics(現在のUNIX)の開発に携わったケン・トンプソンが、BCPLを基にB言語を作り上げます(1969年)。MulticsではPL/Iが使われていたものの、UNIXはミニコンで開発されていてスペック不足だったためアセンブラが使われていました。B言語はUNIXを高級言語で開発するために誕生しました。B言語はUNIXとともにトンプソンとデニス・リッチー、ブライアン・カーニハンの手によって改良が加えられ、C言語へと生まれ変わり、プログラミング言語・そしてOS開発言語のデファクトスタンダードの地位に居座ります。

パソコンにおいては、8ビットマシン時代にはOSの代わりにBASICが起動したため、BASICが主力でした。
16ビット時代にはようやくOSを搭載できるようになり、BASICとアセンブラ以外の選択肢が出てきました。その中でも特筆すべきなのは、Pascalを利用していたLisaでしょう。Appleが開発を手がけ、商業的には失敗した製品でしたが、Mac OSを開発するのに用いられた関係で、初期のMac OSはPascalで開発されていました。といってもこのPascalは、開発したNiklaus Wirth(ニコラス・ヴィルト)自身がオブジェクト指向の拡張を施したObject Pascalでした。
この拡張版はMS DOSのTurbo Pascal用としても採用されます。こちらは独自に進化を遂げてDelphi言語と名前を変え、C#へと繋がっていきます。
その後Mac OSはC/C++へと移行し、Mac OS XでObjective-Cに移行しています。
WindowsはC#が存在しますが、OSの開発は依然C/C++です。

パラダイム


プログラミング言語は、コンピュータの制御を抽象化する際の手法にも焦点を当てて様々なものが作られてきました。
 

 
プログラミング言語は、コンピュータの制御を抽象化する際の手法にも焦点を当てて様々なものが作られてきました。例えば、gotoによる制御フローを専用の構文によって見やすくしたり、汎用性の高いコードを外部ファイルに追い出してそのファイルへの参照を記述し、別のプログラムで同じルーチンを書くという手間を省くモジュラプログラミングなどが登場しました。
ALGOLが登場するまでは実質命令型の非構造化プログラミングというパラダイム一択でした。
命令型とは、文字通りコンピュータに実行させる命令を書いていくプログラミング手法です。もうちょっと言うと、ある目的を達成するためのアルゴリズムをプログラミングしていきます。ここまでに出てきたアセンブラ、Autocode、FORTRAN、ALGOLはすべて命令型です。

非構造化プログラミングは、単純な条件判定と強制分岐のみでループやサブルーチンなどを実現するものです。アセンブラはマクロで実現できるものもあるのでともかくとして、機械語というのは非構造化プログラミングそのものです。プログラマーが直接機械語を扱うことがなくなったこの時代、条件分岐だけでも誰も文句言いませんし、誰も見ることがないから読みにくくたって構わないわけです。ちなみに、当然ながら構造化プログラミングが出てくるでは非構造化しかありませんでしたから、構造化プログラミングの定着に伴って、区別のために付けられた名称です。それゆえの「非」ということです。

ALGOLは構造化プログラミングの第一号で、後の構造化プログラミング言語に多大な影響を与えています。コードの見通しを向上し、実行するコードを選択するにも繰り返すにも専用の構文を使い、様々なアプローチを提供するのが構造化プログラミングです。このパラダイムが定着すると、非構造化言語を激しく非難する人が現れましたが、プログラムの任意の位置に移動できるという柔軟性の高さと、構造化を徹底した言語でも非構造化言語的な機能が残っていることから、不毛な議論だとする意見が出ています。

LISPは関数型プログラミングといって、ほぼすべてのコードは文字通り関数(処理をしたら適宜値を返すサブルーチン)からなっています。
関数型は文字通り関数が値を受け取って処理してその解を返す、というのを繰り返すことで変数が不要になって、変数への代入ミスが及ぼすバグを排除します。とはいったもののLISPは変数も扱えるので、そのような関数型言語は非純粋関数型言語なんて呼ばれます。

構造化プログラミングをさらに抽象化したのがオブジェクト指向プログラミング、略してOOP(Object Oriented Programming)です。問題をオブジェクト=物として考え、状況に応じてオブジェクトを作りだし、解いていきます。
オブジェクトの設計は、まず最も抽象的で汎用性の高いオブジェクトを用意し、そのオブジェクトの機能を引き継ぎ(継承)つつより具体的で専門的なオブジェクトを目的に合わせて作って...と繰り返すことで、様々なシチュエーションに対応しやすくします。
乗り物でオブジェクト指向を例えるなら、まず最低限の機能として、エンジンをスタート・ストップさせる、加速させる、ブレーキをかける、方向転換する、前進後退を切り替える、人を乗せるスペースなどが必要でしょう。しかし同じ乗り物でも、動力となるエンジンも乗り物によってはエンジンではなかったり、そもそも乗り物そのものには動力がなく、外部から与えられた力で走行するものもあります。
このようにして最低限の機能しか持たないオブジェクトを設計してから、その子孫となるより具体的なオブジェクトを作成して機能を付け足していく、というのがオブジェクト指向プログラミングの手順です。

問題に対する解を求めるためのプログラミング=命令型に対するパラダイムを宣言型プログラミングと呼びます。
宣言型は問題に対する解がどのようなものであるかをプログラミングし、問題と解を結びつける部分(アルゴリズム)は他力本願といえます。
例えばSQLやShellScriptが典型的です。SQLはデータベースへのアクセス方法を与え、データを取得した後どう処理するかはそのデータを受け取るソフトウェアに任せています。ShellScriptはUNIXのあらゆるコマンド(プログラム)の連携や一括実行などの自動処理を定義するためのもので、ほとんどの処理をコマンドに頼っています。とくにShellScriptなどのような、様々な外部コマンドと連携するものをグルー言語と呼ぶこともあります。そういう意味ではAppleScriptもグルー言語といえるでしょう。
ちなみに、ここに例示した言語はドメイン固有言語(Domain Specific Language、DSL)と呼ばれるパラダイムにあたります。ドメインとは領域などの意味で、つまるところ特定の領域の問題を解決することに特化した言語、ということです。SQLはデータベースという領域、ShellScriptやAppleScriptはアプリケーションとの連携という領域のための言語です。DSLは宣言型の典型的な例です。
このほかの宣言型プログラミングにはLISPのような関数型、Prologなどの論理プログラミングや制約プログラミングがあります。

関数型はすべてを関数として扱うことでプログラミングするというものです。
純粋な関数では、入力に対してソースコードで定義した通りに出力します。これが宣言型に分類される所以です。
例えばある数の階乗を求めるには、1と2をかけ算して、「その答え」と「2の次の数」のかけ算を、「~の次の数」が求めたい数になるまで繰り返します。
総和なら階乗を求め方のかけ算をたし算にすれば求まりますが、こちらは求めたい数nとその次の数をかけ算して2で割る...つまりn×(n+1)÷2という公式ですぐに求められます。
もう少し実用的なプログラム、データの整合性検査(チェックサム、MD5、CRC、SHAほか)や可逆圧縮(圧縮前の状態に戻せるもの)などもある決まった計算で行われていて、入力が同じ値なら出力も同じ値になり、純粋な関数です。
関数型言語も言ってしまえばこれらと同じで、入力は答えを求めたい数n、関数は公式、出力はその答えという形で対応します。
純粋でない関数は、どこかで設定した値を参照して、それと入力を元に答えを出力します。参照している値が変更されれば、入力が同じでも出力が変わります。
例えば、今日の日付はパソコンに設定された日付をOSに問い合わせるか、インターネット経由でタイムサーバに問い合わせることで求めます。問い合わせ方は決まっていても日付は刻々と変わるので純粋でない関数になります。

結局関数型言語のなにが嬉しいのかというと、構造化プログラミングやオブジェクト指向でもなしえないレベルまでプログラムを小さくし(モジュール化、モジュライズ)、なおかつその汎用性が非常に高いということです。これは高階関数と部分評価、遅延評価がもたらしてくれます。
高階関数は関数そのものを値として引数に渡したりできます。関数を受け取った関数はそれを利用してより複雑な処理を実現していきます(ボトムアップ)。
部分評価は引数の一部だけが定まった関数を作りだします。つまり関数は引数をすべて適用する必要はありません。
遅延評価は必要なときだけ式が評価される仕組みです。普通では分離できないレベルまでモジュライズを可能にしてくれます。また、必要なときだけ計算されることから、無限の要素を持つ配列をシンプルに表現し処理することができます。反面、式がいつ評価されるのかが分かりにくくなったり、処理速度低下の原因にもなります。
純粋な関数では外部からの影響を受けないので、外部からの意図しない操作によるバグを減らすこともできます。
そしてなにより、膨大な量のfor文やcase文などの呪縛から逃れることができるということもまた大きな魅力でしょう。

制約プログラミングは、条件を満たすアルゴリズムを見つけだすためのプログラミング手法です。
プログラムを設計するとき、特定の問題から得られる解が膨大な数にのぼることもあります。その中から、特定の条件を満たす解を得るためのアルゴリズムがほしい、ということも結構あります。
ここまでの説明では、条件判定を逐一折り込みながら解を得るプログラムを書くしか手段はありませんが、条件が込み入ってくるにつれてプログラムは非常に複雑になり、なおかつ汎用性に乏しくなるというデメリットがあります。
この場合、アルゴリズムの設計と条件を分離してしまい、アルゴリズムはさておいてまず解を生成することを繰り返し、条件を満たす解を得たら、見つかった解と条件を利用してアルゴリズムを設計するのが簡単です。
制約プログラミングは、このうちの「条件」を指定するのに用いられます。また、アルゴリズムを考慮せずに解を得る部分を論理プログラミングといいます。

論理プログラミングについてもう少し詳しく見てみましょう。
論理プログラミングは、多くの問題が理論として表現できることに着目しています。問題を解くには、既存の理論で説明がつくかと言いかえることができます。それを論理=真偽で証明します。証明する機能は実行環境に備わっていて、プログラマは理論を定義していくだけで済みます。
関連記事

0件のコメント

コメントの投稿

新規
非公開にする

0件のトラックバック

トラックバックURL
http://harukazehajime.blog115.fc2.com/tb.php/126-c4709e0d
この記事に対してトラックバックを送信する(FC2ブログユーザー)

Appendix

プロフィール

さくらゆーな

Author:さくらゆーな
鉄道熱が再燃して、撮影に模型にいろいろやってます。
最近反核運動に偏ってるのを反省したいけど
知れば知るほど極悪非道な界隈で止まらない…

カレンダー

05 | 2017/06 | 07
- - - - 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 -

+ アーカイブ
 

最近の記事

カテゴリー

検索フォーム


キーワード

カウンター

トータルカウンター
現在の閲覧者数:

ads3

Mac ソフトのことなら act2.com

Make a donate

もしこのブログを気に入っていただけたら上記アフィリエイトプログラムか下のPayPalでブログ・サイトの維持にご協力ください。

donationPrice

ブロとも申請フォーム

この人とブロともになる

ブログランク

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。