制御の基本3構造
さて、厳密には2〜4のどれか、は問いませんが(笑)、ここから制御の基本構造の解説に入っていきます。
もう一度繰り返しますが、通大の「コンピュータ」のテキストの最大のミスは
このテキストローカルの「疑似コード」で抽象的にプログラミング言語を解説しようとしている
この一点に尽きます。
しかも、その疑似コードの実態は「Pascalそのものだ」と言うことも既に指摘していて、いわゆる通常の意味での疑似コードそのものの「良さ」は丸っきり失われている、んです。
そんなまだるっこしい事をするんだったら「Pascalを」素直に使った方が良い、のです。
注:ちなみに、元々Pascalは「教育用プログラミング言語」として開発された経緯があります。従って、理想的には「一番最初に学ぶべき」プログラミング言語として設計されてはいるんですが、残念ながらそんなに人気が出ませんでした。実用的な分野ではC言語に負けてしまったのです。
理由として、「教育用を念頭に入れていた為」、構文が厳密過ぎて自由度が低い事がプログラマに嫌われた、って事が一つ(その点、Cの方が意外にハッカー好みのデタラメさがあったりする・笑)。もう一つは、C言語は元々UNIXと言うOS設計用言語として開発された経緯があったため、大学/研究所内のUNIXワークステーションの普及に従ってC言語は「MUST言語」になった、と言うのがPascalの不幸でした。
一方、Pascalは初期のApple Macintoshと言うパソコンのソフトウェア開発用言語として使われていた経緯もありますが、Macintoshそのものが価格が高すぎて普及せず、結局、認知度が低いプログラミング言語になってしまったのです。
今まで「プログラムの基本要素」「基本データ型」全て見てきました。が、退屈でしょう(笑)?ツッコミ入れてるこちらも退屈でしゃーない(笑)。
何せ、抽象的な「疑似コード」を用いて「抽象的に解説してる」んだから当然、です。実際「目の前にある何か」を動かして反応見ているわけでもない。こう言う形の「プログラミング言語の学習」ってのは通常「あり得ない」んですよ。
やっぱり目の前に「動いている何か」があるに越したことないです。
さて、プログラミング言語毎に結構バラけている「基本データ型」と違い(もちろん、共通するものも多いですが、違いも結構あります)、制御構造自体は「2〜4のどれか」はともかくとして(笑)、「基本」と言うだけあって、共通点が多いです。
よって、このテキストに準拠する以上、実際のプログラミング言語を登場させてみる、のはこの節が一番適切でしょう。
ではどのプログラミング言語を用いるか?
まず、ハッキリ言うと、テキスト準拠を考えると、通大「公式指定」の4つのプログラミング言語(Fortran、BASIC、Pascal、C言語)はどれもサイテーです(笑)。少なくとも前2者は選ぶべきじゃない(1960年代以前の遺産、です)。そしてPascalのコンパイラは見つかりづらいし、C言語はコンパイラは見つかりやすいんですが、初心者向けじゃないです。
そこで代替案に4つの言語を紹介しておきましょう。
最初に断っておきますが、通大の「レポートが通る」とか「テストが通る」とかそう言う低レベルの話をしてるつもりは丸っきりありません。どっちかと言うと、こう言う経験を元に「一生(何らかの)プログラミング言語と付き合って使っていける」と言うのを目標とします。そう言う大きい目標がある以上、「レポートが通る」とか「テストが通る」なんてのは小さい話なんでどーでもいい、です。
少なくとも、今まで高校数学の窓で見かけた通大生の投稿を見る限り、「目の前のレポート/テストさえ通れば良い」と言う態度がありありで、そんなんだったらそもそも教師なんて辞めた方が良い、です。大体生徒にプログラミング訊かれても答えられないですしね。
いずれにせよ、通大の「コンピュータ」のテキストが古いわ、ある意味システム的に破綻してるわ、だと一見回り道に見えても「別言語を経由した後」対策を考えた方が結果早い、って事です(これは通大数学コースのプログラミング/SE経験者の動向見ても予測可能でしょう)。
ここで紹介する4つの言語はどれも「オープンソース」で「マルチプラットフォーム」で「タダで入手可能」でしかも「高機能」です。
一般に、最低でも 3 種類のベンダーの OS でサポートされていない言語は、どれでもハッキング(注:良いプログラミングの事)にはまずい言語といえます。
もう一つ重要なのは基本的に「インタプリタ」、つまり対話型でのプログラミングが可能なプログラミング言語、を選びました。
もちろん、この4つ全部を覚えろ、ってな気は毛頭ありません。このうちのどれか一つを選んで、そこそこ使えるようになれば、逆にFortranだろうがBASICだろうがPascalだろうがC言語だろうが「何となく」読めるようにはなる、んです(そもそも通大のテキストの本質的なネタは"数値計算"ですから、そんなに言語自体に深い知識が必要ではないのです)。
ただし、要するに「最初の一歩」として、どの言語を選ぶか?と言うのは割に「個人的な好みの問題」ってのがあるんですよ。平たく言うと「見た目」だとか(笑)。そんなわけで万全を期して「4つ」としました。
もう一つの目的としては、「コードの構成法」と言うのは使うキーワード類は違うとしても、大まかに言うと「同じだ」からです。最初期の状態から自分で使わないにせよ、「他の言語の書き方」に目を通しておけば、ここで紹介した言語「以外」に移った時に、あまりビビらなくて済む(笑)。要するに「プログラミング言語に対する勘/慣れ」を早めに増加させる目的もあります。
いずれにせよ、一部の通大生(だと思いたいんですが)は「情報を入手」しても「実行しない」らしい、って事は言えます。ここで情報を入手して「やってみる」と思えるか、あるいは「メンド臭い」と思うか。いつぞや書きましたが「メンド臭い」と思う人はそもそも理系に向いてないんで、数学教師になろう、なんて大それた事は考えない方が無難です。
なお、4つのプログラミング言語の紹介にはサンプルコードを付しておきます。このサンプルコードは通大「コンピュータ」のテキストp.140のPascalでの「Summation」のコードをそれぞれの言語に置き換えてみたもの、です。
本当に1対1対応で、それほど各言語の特徴が出ていませんが、いずれにせよPascal版より「短くなってる」と言う事だけは分かると思います(少なくとも、変数宣言が無い分だけは短くなります)。そして、結果サンプルコードは「どの言語にせよ、同じ結果を返す」と言う事が保証されているので(元ネタのコードが同じ為)、後は「見た目」で好みのプログラミング言語が選びやすくなっているでしょう。
まずは最初に「動く疑似コード」と世界的に評価が高い言語二つを紹介します。
1991年にオランダ人Guido van Rossumによって開発された比較的新しいプログラミング言語。元々はPascal同様に教育目的に開発されて習得しやすい、と言われている。21世紀のBASIC、と呼んでも良い言語である。世界的に評価が高く、人気があるプログラミング言語である。また、GoogleをはじめとしたIT企業でも開発に用いられている程、である。日本公式サイトはPyJUG。 |
コード例
# -*- coding: utf-8 -*-
def Summation():
n = input(u"自然数nを入力してください: n = ")
if n <= 0:
raise "ValueError"
else:
sum = 0
for k in range(1, n + 1):
sum += k
print u"1から%dまでの和 = %d" % (n, sum)
特徴
- まさしく「動く疑似コード」と呼ぶに相応しく、ロジックに集中して非常に短くコードを書き上げる事が可能。
- この短さ、の秘訣のうちの一つは、構文要素にインデント(字下げ)が含まれており、ブロック構造を全てインデントで表現する、と言う特徴があるから、である(何らかのキーワードなり記号が必要ない)。
- 従って、現代的なインデント中心のソースコードの「読み書き」に一番習熟出来るので、「教育用言語」の面目躍如である。
- 基本的にC言語で実装されている(Java版もアリ)。
長所
- ダウンロードすると、オールインワンの開発環境が手に入り、余計なものが必要ない。
- C言語的な記述法の影響を受けていて、C言語に移りやすい。
短所
- 現時点では、日本語の扱いが若干弱い。
- 当面の問題としては、数学的計算をさせる際、ライブラリを明示的にインポートする必要があり、また、計算速度もそれ程速くない。
メーリングリスト
何かPythonで分からない事があったら次のメーリングリストで誰かが親切に答えてくれるかもしれません。
Python MailingList Japan
推薦コメント
もしコンピュータ言語をなにも知らないなら、まず Python から始めることをおすすめします。設計がきれいだし、ドキュメントもしっかりしているし、初心者にもそこそことっつきやすくできています。でも入門言語として最適でも、おもちゃではありません。強力で柔軟で、大きなプロジェクトにもじゅうぶん対応しています。
総評
実は、高校数学の窓でどのプログラミング言語を紹介しようか、と迷って、最後に残った二つの候補のうちの一つがこのPythonだったんです。残念ながら恒常的な数値計算ネタには向かないだろう、ってんで結果Schemeを選んだ、のですが、一般的な意味では「一番書きやすく」かつ「見た目が良い」のはPythonだと思います。つまり、ソースコードの可読性を考えるとピカイチだと言う事です。
ここで、「Pythonが良いな」と思った人はすぐさま次のダウンロードページに進んでPythonをダウンロードして下さい。
Python標準リリース
また、オープンソースらしく、オンラインドキュメントが豊富なのがPythonの魅力です。が、通大のテキストを理解する程度なら、次の二つのオンラインドキュメントをやる程度で十分でしょう。
また、若干古いのですが、次のような入門サイトもあります。
取り合えず、暫くは(と言うか、恐らく最初の二つの文書を勉強するとしても1〜2週間もあれば充分でしょう)上の文書類に取り組んで、それからここへ戻って来てください。では、Python組は、行ってらっしゃい(笑)。
1993年に日本人まつもとゆきひろ氏によって開発されたプログラミング言語。元々UNIX用スクリプト言語(簡易言語の一種)として開発された為、UNIXサーバーとの相性が抜群で、Webアプリケーションの開発にも向いている。日本国内で絶大な人気を誇り、また世界的な評価もうなぎ上りの注目株である。公式サイトはRuby。 |
コード例
def Summation
print("自然数nを入力してください : n = ")
n = gets.to_i
if n <= 0
raise
else
sum = 0
for k in 1..n
sum += k
end
puts '1から' + n.to_s + ' までの和 = ' + sum.to_s
end
end
特徴
- 基本的にC言語で実装されている(Java版もアリ)。
長所
- 日本で設計された為、日本語を含む多言語の扱いが比較的容易である。
- あらゆる形であらゆる言語の「長所」をなるべく取り入れるように設計されている為、かなり短くコードを記述出来る。
- また、基本的な数学的な機能は全てビルトインなので、余計なライブラリを呼び出す必要があまりない。
- 日本生まれのお陰で日本人のユーザー数が多く、結果として日本語で読めるWeb情報が極めて多い。
短所
- 元々、「プロ用」に設計されている為、自分で開発環境を用意しなければならない。
- インタプリタ機能(REPL = Read Eval Print Loop)でさえ、自分で設定する必要がある。
- ブロック構造の終端を
end
を置いて明示的に示さなければならない為、タイプ量が比較的多くなり、気づいてみれば記述したソースはend
だらけになってたりする。 - 計算速度は大して速くない。
メーリングリスト
何かRubyで分からない事があったら次のメーリングリストで誰かが親切に答えてくれるかもしれません。
メーリングリスト
Web雑誌
昔のパソコンのプログラミング雑誌(例えばベーマガとか)よろしく、日本Rubyの会ではWeb雑誌も発行しています。
当然無料なんで、こう言う雑誌を購読しても良いでしょう。
Rubyist Magazine
推薦コメント
教育用の言語としてRubyは最適です。
総評
日本生まれの日本が世界に誇るべきプログラミング言語、です。日本製のプログラミング言語でここまで世界で人気を博したものはかつて存在しませんでした。
サンプルコードを見ても分かると思いますが、殆どPythonと変わりません(
end
がある分だけちょっとだけPascalっぽいです)。実際、「使われ方」はPythonと競合してて、Pythonの最大のライバル、です。世界的情勢では今の時点ではPythonの方が人気がありますが、今後数年間で立場が逆転する可能性さえあります。
Webでの使用例も多く、気づかないかもしれませんが「Rubyで書かれたWebサイト」なんかも知らず知らず使っている可能性さえあります。
武田先生もRubyを学んでいた事がある、とかどっかに書いてたと思うんで(当然、僕より遥にRubyに詳しいと思います)、レポート問題の丸投げやるんだったら「Rubyで書いてみて」「質問とソースを投稿して」「あとで十進BASICになり何なり自分で訳してみる」んだったら武田先生も回答してくれる可能性があるでしょう(と言うか、「最後は自分で訳してみる」くらいアタマ使え、って事です)。
ここで、「Rubyが良いな」と思った人はすぐさま次のダウンロードページに進んでRubyをダウンロードして下さい。
ダウンロード
また、Rubyの場合、WebチュートリアルがPythonのものと比べても「非常に上出来」だと思います。非常に分かりやすい「プログラミング入門」が公開されていて、初心者向けですね。これを終わらせれば通大の「コンピュータ」のテキストを読解するのも簡単だろうと思います。
また、Rubyの難点、つまり「開発環境選択」とか「インタプリタの設定」なんかもこのチュートリアルに記載されているんで、「言われた通りに設定していけば」何も問題は生じないと思います。
プログラミング入門 - Rubyを使って -
ちなみに、上記のチュートリアル(日本語版)は、千葉大学の工学部のプログラミング未経験者の為の初級者向けテキスト、として実際使われていた実績があるようです。
分量もそんなに多くありませんので、一日一章進めていっても2週間以内で終わる計算となります。
取り合えず、暫くは上の文書に取り組んで、それからここへ戻って来てください。では、Ruby組は、行ってらっしゃい(笑)。
注:他にもWindows向けのRubyの開発環境設定には以下のような方法がある。
- Rubyそのもののインストール法→Rubyの準備を参照。写真入りで解説されていて、比較的初心者にも分かりやすい記述である。
- Windowsユーザー用Ruby開発環境→RDEを参照。原始的なテキストエディタであるWindows備え付けのメモ帳(Notepad)でもプログラムを書けなくはないが、色々とメンド臭い。そこで「Rubyでプログラムを書く為の」色々な機能が付いた統合開発環境(IDE=Integrated Development Environment)があると便利。RDEはRubyに特化したIDEである。亀田は未使用だが、プログラミング初心者にもお薦めならしい。
これら二つの言語(PythonとRuby)は「動く疑似コード」と呼ばれているだけあって、「ロジックに集中して書く」事が可能です。と言うか「ロジックだけ」書けば良い。工学的な「余計な要素」が基本的に存在しません。
通大のワケの分からない「疑似プログラム」と違って、通常「疑似コード」と言うのは、繰り返しますが、「汎用的なロジックだけを抜き出して書く」のが特徴なのです。従って、これらの言語の人気は「わざわざ疑似コードを紙の上で書くくらいだったら初めからPythonやRubyで記述してしまった方が早い」と言う事実に裏付けられています。実際、これらで一旦「目の前で動かしてみて」速度的に問題が生じた場合、C言語等で「部分的に書き直してみる」と言うのがプロの現場でも良くある、と言う話です。通大のワケの分からない「疑似プログラム」を使って書いて考えるよりも「実践的だ」と言う事ですね。
残り二つの言語は既にここで紹介して使っているもの、です。が、改めて紹介しておきましょう。
1975年にMIT(マサチューセッツ工科大学)のガイ・スティールとジェラルド・ジェイ・サスマンによって開発された関数型プログラミング言語。Lisp方言の一つである。元々は理論的実験の為に作成されたが、教育用プログラミング言語として改良され、MIT(マサチューセッツ工科大学)をはじめとした世界中の様々な大学の情報工学系の授業で用いられている。日本での主な使用大学は広島大学、東京工業大学、東京大学等。 |
コード例
(define (Summation)
(display "自然数nを入力してください : n = ")
(let ((n (read)))
(if (<= n 0)
(error n)
(do ((k 0 (+ k 1))
(sum 0 (+ sum k)))
((> k n)
(for-each display
(list
"1から " n "までの和 = " sum "\n")
)
)
)
)
)
)
特徴
- 元々、Schemeの元ネタ、Lisp自体が工学出自の「設計の為に設計された」プログラミング言語ではなく、数理論理学者であるアロンゾ・チャーチ等によって提唱された数学理論、ラムダ算法を元とした純粋な数学から来ている。
- SchemeはそのLisp言語族の中でも一番シンプルで小さい方言である。
- 従って、「計算モデル」を論じるのには一番適切で、また、数学を「計算」に置き換えるのも一番面倒が少ない。
- Python、Rubyのように、基本的に「単一の公式実装しか存在しない」わけではなく、Schemeはキチンと公式に文書として定義されているプログラミング言語である。実装数はこの世にフリーのものから商用のものまで合わせて10個以上存在していて、好みの実装が選べる。
- 故に「公式な仕様書が存在し」「複数ベンダーによる複数の実装が存在している」以上、C言語やPascal等と同等な、「メジャー言語」である(情報工学系に於いての認知度、と限定はされるが)。
- 実は実装の存在数自体はひょっとしてC言語やPascalよりも多いかもしれない。これも「メジャー性」を裏付けている。
- お薦めがオールインワンの実装、DrSchemeだが、要するに別実装もたくさんあるので、その辺は好みで良い。
- なお、日本では、プロ用目的で作られ、Webアプリケーション作成で定評のある、日本製の実装Gaucheが特に人気がある
(がWindowsでは基本的には動かない)。Windows用にはGaucheboxと呼ばれるオールインワンの開発環境が用意されている。
利点
- 構文らしい構文が一つしかない。
- その唯一の構文がS式と呼ばれる
(手続き 引数)
と記述する表記法である。SchemeでのプログラミングはそのS式を入れ子状に引数内に記述していくだけ、であり、原理的にはMicrosoft Excelの関数と大して変わらない単純なものである。 - 従って、自由度が高く、割に「デタラメに書いても」平気で動いてくれる。
- また、数学出自らしく、ビルトインの数学関数も豊富で、また論理構造の一貫性も高い。
- 実装にもよるが、現代のPCの環境では、基本的に計算は高速である。
欠点
- とにかく括弧だらけで、一般的感覚で言うと「読みづらい」。
- また、「一貫性が高い」のトレードオフが前置記法(ポーランド記法)と言う数理論理学出自の数式記述法で、慣れないとちょっとした数式さえも書きづらい。
推薦コメント
LISP は、それをモノにしたときのすばらしい悟り体験のために勉強しましょう。この体験は、その後の人生でよりよいプログラマーとなる手助けとなるはずです。たとえ、実際には LISP そのものをあまり使わなくても。
Cがコンピュータがどう動作するかのモデル化に最も適した言語とすると、Lispは計算というものがどう振る舞うかをモデル化するのに最も適した言語だ。ほんとのことを言って、Lispについて多くのことを知る必要はない。一番シンプルでクリーンなSchemeを使い続けることだ。他の Lisp方言はライブラリやらツールやらを備え、C++やJavaが持つような大きく複雑なプログラミング環境へと成長している。そういう部分については知っている必要はない。ただSchemeでプログラムを書ける必要がある。
僕は、Schemeの開発こそ、コンピュータ・サイエンスの典型的なセンスの一つではないかと思うのである。それまでは、LISPの考案者McCarthyのまやかしともいえる「変数の動的なスコープ」に、皆がだまされ続けていたわけである。それを、「静的スコープ」でLISPが作れるということを身を持って証明したのが、Schemeの開発であった。Schemeの開発は様々な要素から成り立っている。まず、静的スコープの方がλ算術の理論との整合性がよいという認識がある。そのような認識を得るには、もちろん、λ算術を知らなくてはならないけれども、それほど数学的なことまで知る必要はない。また、いくら理論との整合性がよくても効率よく実現できなければどうしようもないから、静的スコープを効率よく実現するための技術が必要となる。さらに、いくら理論との整合性がよく実現の効率がよいとしても、プログラミング言語として、わかりやすく使い易いものでなければならない。そのためには、シンタックスを工夫したり、環境を整えたりしなくてはならない。以上のような様々な問題を克服して初めて、静的スコープが現実のものとなり、Schemeが本物のプログラミング言語となったのである。
総評
Lispそのものに付いては大した解説はいらないでしょう。通大の「コンピュータ」のテキストにも解説は書いてありますし。p.20辺りに次の記述があります。
1958年にマサチューセッツ工科大学(MIT)のジョン・マッカーシーJohn McCarthyを中心とした人工知能研究グループによって考案されたプログラミング言語で、この分野の研究には欠かせない言語です。LISPはLISt Processorの略と言われています。
LISPは言語名の由来からも分かるように、リスト(節点と枝を持ち、情報と情報間の関連の両方を表すデータ)を主なデータ構造とする言語で、節点と枝に適当な意味を持たせることにより広範囲の情報をコンピュータ処理の対象にできるのが特徴です。
応用分野には図形処理、数式処理、自然言語処理、知的ゲーム、知的な推論を必要とする質問システム(エキスパートシステム)等があります。これらの分野では、必ずしも常に成立するとは限らないが、多くの場合に問題解決に有効な働きをする経験的知識を使ってプログラムの実効効率を上げたり、その結果を見てさらにプログラムの改良したりすることが良く行われます。このようなプログラミングの方法を発見的プログラミングheuristic programingといいます。これに対して、常に成り立つ知識を使って問題解決の手順を組み立てていくことをアルゴリズミック・プログラミングalgorithmic programmingといいます。
もはや後半になると何の事を言ってるのかサッパリですが(笑)、まあ、Schemeはこう言ったLisp言語族の一つ、です。
Lisp言語族は恐らく「史上最強のプログラミング言語」で、前出のPython、Ruby等もこの「Lisp言語族」の影響を受けています(特にRubyがその気が強いですし、作者もそう語っている程、です)。
欠点としては、既に挙げましたが、「前置記法」と「括弧の多さ」ですね。それに加えて「数学ベース」なんで、「非常に強力な数学的記述法」を用いる代わりに、「数学的過ぎる」辺りが一般的に人気が出ない理由でもあります。ただし、「数学的」を嫌うのは「数学教員育成コースの学生」としてはおかしな話です。自ら「数学が出来ない」って言ってるようなものですから。
ちなみに、面白い現象なんですが、大学の情報工学関係出身者でこの「数学性」でLispのファンになる人間は多いんですが、反面、理学部数学科出身者の方は「Lispを知らない」と言うケースが結構多い、ってのにビックリします。
大学内は縦割りなんで「学部をまたいで情報が広がっていかない」のか、あるいはやっぱり「餅は餅屋」なのか。逆にBASICは「数学者が直接作った(かつ設計がマズい言語)」なんで数学関連で用いられるケースはいまだあるようですが、もったいない話、です。
実際、ちょっと慣れるまで時間がかかるのは事実ですが、反面、「括弧の多さ」と言うのは慣れればさほど気にならなくなります。
大体、Schemeに慣れてくると、上のサンプルコードは「脳内変換」されて次のように読まれてたりするのです。
define (Summation)
display "自然数nを入力してください : n = "
let n (read)
if (<= n 0)
error n
do (k 0 (+ k 1)
(sum 0 (+ sum k)))
(> k n)
for-each display
list
"1から " n "までの和 = " sum "\n"
括弧外してみると、実は形式的にはPythonやRubyのサンプルコードと大して変わんない事に気づくでしょう。例外は「反復」であるdo〜以下でこれは確かに見づらいと僕も思うんですが、概してSchemeユーザーはdoなんて使わないんで構わないのです。じゃあ、何でここで使ったのか、と訊かれるでしょうが、単に元ネタのPascalのコードと対比させる為、だけです。通常こんな書き方はしません。
いずれにせよ、括弧は大した問題じゃなく、慣れれば「消えて見える」ようになります。
弟子が尋ねた。「先生、私は先生がカッコをまるで魔術師のように扱っているのを常々敬服しています。どうすれば先生のようになれるのでしょうか?」
師「えっ? カッコ? あ、そうか。そんなものもあったな。いやあ、 すっかり忘れておったわ」
とにかく、Schemeは「括弧の帳尻合わせで」ソースコードを書いたり読んだりして行くのではなくって、あくまで「インデント」(字下げ)で読み書きしていくのです。
構文上は自由度が高いSchemeですが、括弧の数の多さにより、逆説的に「Pythonのように」インデントが極めて重要な言語、となっています。インデントが無ければ「書くのも」「読むのも」非常に大変になる、と言う事を表しているのです。
また、通大のテキストの記述によると「Lispは人工知能向け」と言う事が仄めかされているので、
「人工知能、って難しい分野でしょ?だったらSchemeも難しいんでしょ?」
と不安がる向きもあるでしょうが、全然関係ないです。と言うのも「人工知能」は難しい研究分野ですが、イコールSchemeが難しい、ではない、と言う事です。
何故なら、「難しい研究を難しい道具でやる」ってのはバカのする事です。正解は「難しい研究は簡単な道具でやる」です。研究分野が難しいわ、使う道具も難しいわ、じゃ普通に考えると行き詰まっちゃうんですよ(笑)。従って「難しい研究分野こそ」簡単な道具を使わないとやってられない、んです。BASICは「簡単だ」ってイメージがありますが(イメージだけ、です)、実際「人工知能」でBASICが使われている、なんて話は聞かないでしょう?見た目はともかくとして、BASICより簡単な言語がLisp言語族なのです。
ここで、「Schemeが良いな」と思った人はすぐさま次のダウンロードサイトに進んで次のソフトウェアをダウンロードして下さい。
魔法言語リリカル☆Lisp
これはScheme実装ではないのですが、チュートリアルとしてはピカイチ、です。全12章のアドヴェンチャーゲームソフト、として作成されているので遊びながらSchemeの基礎が学べます。これも2週間程度で終わらせる事が出来るでしょう。京都工芸繊維大学の学生さんの作品です。
注意点としては、テキストエディタが必要となります。そのうちC言語を使うにせよ、「しっかりとした」テキストエディタがどの道要り用になるんで、ここでは魔法言語リリカル☆Lispとリンクが出来るxyzzyを推薦しておきます。xyzzyはWindows用の超高機能なフリーのテキストエディタ、です。
xyzzy用のプラグインは以下から入手して下さい。
xyzzy lyrical-mode
xyzzy lyrical-modeを解凍すると、中にlyrical.lと言うファイルがあるんで、そこに記述された説明に従って設定して下さい。
取り合えず、魔法言語リリカル☆Lispに取り組んで、それからここへ戻って来てください。
では、Scheme組は、魔法言語リリカル☆Lispで遊んでらっしゃい(笑)。
1993年頃、ニュージーランドのオークランド大学のRoss IhakaとRobert Gentlemanにより作られた。豊富な統計解析用関数をビルトインで持つ統計解析用プログラミング言語である。ただし、両2名が言語自体をデザインしたわけではなく、これは元々米国AT&Tで開発された商用の統計解析用言語Sのフルスクラッチのコピー版である。 |
コード例
Summation <- function() {
n <- readline("自然数nを入力してください : n = ")
if (n <= 0) {
return (NA)
} else {
sum <- 0
for (k in 1:n) {
sum <- sum + k
}
cat("1から ", n, " までの和 = ", sum, "\n")
}
}
特徴
- ここに紹介した4つのプログラミング言語の中では、制御構造の記述法が一番C言語のそれに近い。
- その大きな理由は、元々Sを開発した米国AT&TがUNIXとC言語を開発した会社だから、である。
- UNIXの端末による対話型環境が探索型統計解析と相性が良い為、Sは元々UNIX用の統計解析用途のプログラミング言語として設計された。
- Sはアメリカ計算機学会の1998年度ソフトウェアシステム賞を受賞している。
- Rは文法的にはそのSのクローンだが、内部的にはSchemeの影響を濃く受けている。
- 従って、「Cの皮を被ったScheme」である。
- SもRも現在では世界中の統計解析専門分野、例えば医療統計の分野、経済予測の分野、等で幅広く用いられている。日本の大学での文系の統計ではSPSSの独断場だが、理系ではコスト面からバッチ式で商用のSASよりRが使われるケースが徐々ではあるが増えている。
利点
- 統計解析用言語、と銘打つだけあって、疑似乱数の精度が高く、他のプログラミング言語のビルトイン乱数の追従を許さない。→メルセンヌ・ツイスタ法
欠点
- 汎用プログラミング言語ではない為、ファイルの読み込みや綺麗な表形式のデータの書き出し、表示には強いが、一方、一般的なプログラミング言語では当たり前の単純な入出力が意外と弱かったりする。
総評
この中では異端の言語だとは思います。統計解析用ツールと言えば良いのか、プログラミング言語と言えば良いのか……。
しかしながら、見方を変えてみると、プログラミング言語は「プログラムを書く道具」なのはともかくとして、「それ自体がプログラム」でもあるわけです。この境界線は、GUIのアプリケーションとはイメージが違い、コマンドラインのアプリケーションでは極めて曖昧です。
また、Rでは制御構造の記述法が極めてC言語に近い事もあって、これを終えた後、C言語「には」移りやすいでしょう。この「C言語臭さ」が好みが分かれるところではありますが(ちなみに、亀田はこのC言語臭さが大っ嫌いです)。
一方、通大生は統計を苦手とする人も多いようで、どうせだったら「プログラミングの勉強+統計」を両方一緒に勉強する、と言うような一石二鳥を狙う人がいてもいいだろう、って事で、まあ、ある種「オマケ」ですが、Rに関しても紹介しておきました。
Webチュートリアルに関しては……難しいですね。恐らくR-Tipsが一番良いのではないでしょうか。ただし、これはここで紹介した他の言語と違い、1〜2週間で終われるような分量じゃない、と思います。
しかしながら、これをやってのけたら……まあ、通大の「コンピュータ」のテキストを読まずして通大の「コンピュータ」のテキストを全て理解してしまう可能性があります。と言うのもR-Tipsは統計関数の使い方は当たり前として、プログラミング入門、通大のテキストの肝である「数値計算法」の記述もあり、要するに「てんこ盛り」なのです。恐らく、通大の「統計」用の参考書+「コンピュータ」くらいの内容はあるでしょうね。
まあ、そんなわけで、ここでRを選んだR組は帰ってこなくてもいいかもしれません(笑)。ダウンロードや設定はR-Tipsに記述があるんで頑張ってください(笑)。
なお、ここではこれら4つの動的型付け言語を利用して通大の「コンピュータ」のテキストを読み解いていきますが、それでもFortran、BASIC、Pascal、C言語をやりたい、って人もいるでしょう(あるいは、レポート/テスト対策の為には明らかに必要でしょう)。そう言う人の為には最後にコンパイラ等の入手方法や参考書等を紹介した付録を付けておくので、「自習」して下さい。Pascalはともかくとして、Fortran、BASIC、C言語と言う「全く性質が違う」言語でこのテキストを解説するのは不可能だと思います(そして、Pascalは入手出来さえすれば、テキスト読解はそんなに難しく無いでしょう)。
では、4つの動的型付け言語を使ってテキストの読解に入ります。また、「まだ選べない」人にとっても、「制御構文の好み」でこれ以降の節ですんなりどの言語にしようか選べるとは思います。
本題です。
コンピュータは、プログラムの中で次のように書かれているとき、
- 命令文1
- 命令文2
- 命令文3
- ・・・
- ・・・
上から順番に命令を実行していきます。この命令の逐次処理がコンピュータの基本です。このテキストでは、上のように1行に1命令を書くことを原則とし、それを上から順に逐次実行していくものとします。
これは本当に基本です。どんな言語でも、「上から順番に命令を実行していきます」。割に単純な事なんですが、ソースを読む場合やプログラムを組む場合、「これを忘れる」事がままあるワケです。
逆な言い方をすると、以降の分岐や反復の存在意義は、この「バカ正直に上から順番に命令を実行していく」コンピュータの処理の流れを若干変化させる為、だけにあります。だから「制御」なんですね。
簡単な例題を考えてみます。次の計算を順番通り行うとしましょう。
$1 + 2$……(答え)3
$2 \times 3$……(答え)6
$5 - 8$……(答え)-3
$9 \div 2$……(答え)4余り1
左がプログラムで右が計算結果だとして……仮に「上から順番に計算を実行しないで」右の答えが羅列されたらどうなるでしょう?「計算は正しい」のに、「順番がグチャグチャ」……。そんな事はあり得ませんね。と言うか、あっちゃ困る、のです。
つまり、計算の指示順と計算結果の表示順は「同じ並びじゃなきゃ困る」ってのが大原則なんです。これは上のような「単純計算」じゃなくても原則は同じ、です。それが計算機の使命、なんです。
バカバカしいかもしれませんが、上の例に従って、4つの言語での逐次処理プログラムの例を見てみます。
|
|
|
|
表示指定なんかが違ったり、特に割り算でどこまでの値を返すのか、言語によって違いはありますが、しかしながら、「上から順番に計算していって返す値も同じ順」だ、と言う事が分かるでしょう。
また、4つの言語のそれぞれのソースも基本的には全く同じで記法意外は殆ど変わりません。
しつこいようですが、これが「逐次実行」でプログラミングの基本中の基本です。
あらゆるプログラミング言語は上から順番に命令を実行していく
これを念仏のように唱えてください。これが分からないと、プログラミングではドツボなのです(しかも、アタマで分かっても「感覚的に」分からないケースが多い、のです)。
何かしら作成したプログラムが「思った通り動かなかった場合」、分岐/反復等の制御を疑うのは当然なんですが、分岐/反復は必ずその「ブロック」(実行範囲)を持ちます。そしてその「ブロック内」での記述に於いて「自分が企画した通りの順番に並べたのか?」。ブロック内に於いてもこの「逐次実行のルール」と言うのは厳然として存在するんで、そこでの「並び」、あるいは「命令の配置」は必ずチェックする必要がある、のです(プログラミング初心者はこの辺で必ずミスをする、んです)。
このような上から順番に命令を実行するだけで、最終の目的に達することができれば、それにこしたことはありません。しかし、現実にはコンピュータになんらかの状況判断をおこなわせて、それによって処理の流れを変えてやらなければなりません。そのためにあるのが、分岐処理です。
分岐の基本は、
もし (命題) ならば 命令文T
さもなくば 命令文F
または、
if (命題) then 命令文T
else 命令文F
と書かれるものです。このかたちの制御で、なんらかの判断をコンピュータに行わせることになります。これは、"もし"、"if"の後にある(命題)が真のとき、命令文Tを実行し、その(命題)が偽のとき、命令文Fを実行します。すなわち、(命題)の真偽によって2つの命令文のうちのどちらか一方のみを実行します。この後は、どちらの命令文を実行したにせよ、次に書かれた命令文を実行することに注意してください。この分岐の変形として、
- もし (命題) ならば 命令文T
または、
- if (命題) then 命令文T
と書かれる、(命題)が真のときのみ命令文Tを実行する制御の仕方もあります。
さて、ある命題が真のとき実行したい命令が1文で記述されるならば、上の形だけで十分ですが、いくつか命令を書きたいときはどうするのでしょうか。これは複文という考え方を用いて解決されます。
もし (命題) ならば {
- 命令文T1
- 命令文T2
- ・・・
- ・・・
- 命令文Tx
}
さもなくば {
- 命令文F1
- 命令文F2
- ・・・
- ・・・
- 命令文Fx
}
と書いて、(命題)が真のとき"{"と"}"で囲まれた、命令文T1、命令文T2、・・・、命令文Txまでを順に実行し、偽のときは、やはり"{"と"}"で囲まれた、命令文F1、命令文F2、・・・、命令文Fxまでを順に実行します。ここで"{"と"}"で囲まれた一連の命令文を、一つの命令文であると解釈すれば、前の書き方と整合がとれます。これを複文といいます。
後半辺りにCが混じってきますね(笑)。"{"と"}"で囲んでブロックを表現するのは基本、Cから来ています。
ここで実際、4つの動的言語の分岐の記述法を上の例に倣って見てみましょう。
Pythonの分岐
if 命題 :
命令文T1
命令文T2
・・・
・・・
命令文Tx
else:
命令文F1
命令文F2
・・・
・・・
命令文Fx
非常にシンプルです。殆ど上で解説されている分岐と変わらないでしょう。
Pythonの場合、複文をまとめる「ブロック」は"{"と"}"で表現せずに、全てインデント(字下げ)で行います。行頭が揃っている部分が「ブロック内部の命令」と言う意味です。また、ifやelse等の分岐キーワードの最後には必ずコロン(:)を付けます。また、命題を"("と")"で囲む必要もありません。これがPythonの特徴です。
もっとも、インデントに関して言うと、Python備え付けの開発環境(IDE)がコロン(:)を入力した時点で「この後にはブロックが来る」と判定して勝手に字下げしてくれます。従って、そこまでプログラムを書く側が一々インデントを気にしなくても良いのですが、それでもインデントがどう付けられるか、注意して見てください。
Rubyの分岐
if 命題
命令文T1
命令文T2
・・・
・・・
命令文Tx
else
命令文F1
命令文F2
・・・
・・・
命令文Fx
end
Rubyも形式的にはPythonと殆ど変わりません。命題自体を"("と")"で囲む必要はありません。
Pythonとの違いのポイントとしては、
- if、等のキーワードによる構造を記述する際は、必ず最後は
end
で終わらないとならない。 - if、else等を記述した行にコロン(:)を書く必要が無い
と言う辺りでしょうか。
Schemeの分岐
Schemeの分岐はPythonとRubyに比べてちょっと変わっています。
と言うより、通大のテキストの説明には一番適合するやもしれません。
(if (命題)
(命令文T)
(命令文F))
これが分岐の基本形です。ただし、通大のテキストやPython、Rubyと違って、まずは
else
が必要無い、です。(命題)が真であれば即座に命令文Tが実行されますし、(命題)が偽だったら命令文Fが即座に実行されます。そしてこれが意味するのは、理論的にはelse
、ってのは要らないのです。で、基本形はこのまま、なんですが、通大のテキストで言うところの「複文」を実行させる際には、別のキーワードが必要となります。
(if (命題)
(begin (命令文T1)
(命令文T2)
(・・・)
(・・・)
(命令文Tx))
(begin (命令文F1)
(命令文F2)
(・・・)
(・・・)
(命令文Fx)))
実は、Schemeではブロック内で逐次実行する場合は明示的に
begin
と言う命令を使わなければならず、これが通大のテキストで言う"{"と"}"の役割を果たしています(と言うか、もっと本当の事を言うと、Schemeにはブロック、複文と言う概念すら存在しないんですが、今のところはそう言う解釈をしておいて構いません)。Rの分岐
if (命題) {
命令文T1
命令文T2
・・・
・・・
命令文Tx
}
else {
命令文F1
命令文F2
・・・
・・・
命令文Fx
}
これが一番通大「コンピュータ」のテキストに書かれている構文例にクリソツですね。
(と言うより、C言語のものにクリソツなんですが)
コンピュータが得意とすることの1つに、繰り返しがあります。人間は単純な反復処理を嫌いますが、コンピュータは文句一ついわずに黙々と、何千回、何万回であろうと、いいと言われるまで繰り返してくれます。プログラムでは、これをうまく使わなくてはなりません。
基本となる反復処理は、その繰り返し回数がすでに分かっているときに使われる、次のようにかかれるものです。
iをmからnまでとして次を繰り返す
{
- 命令文1
- 命令文2
- ・・・
- ・・・
- 命令文x
}
ここで、iは整数型変数、mとn(m≦n)は整数値(整数型変数を使うときもあります)です。これによって、まず変数iにまず変数mを代入して、それから"{"と"}"で囲まれた命令文を上から順に、命令文xまで実行します。次に変数iの値を1だけ増加して、同じ"{"と"}"で囲まれた命令文を実行します。これを、変数iの値がnになるまで繰り返し、変数iの値がnより大きくなれば、括弧内の命令文は実行されずに制御はこの後に書かれている命令文に移ります。すなわち、
- i = m として{・・・}内を実行する
- i = m + 1として{・・・}内を実行する
- ・・・
- ・・・
- ・・・
- i = n として{・・・}内を実行する
と記述したことと同じことです。結局"{"と"}"で囲まれた一連の命令文を(n - m + 1)回繰り返すことになります。この変数iを通常、ループの制御変数といいます。数学で添字といえば、文字i、jが一般にはよく用いられます。制御変数によって、何回目の繰り返しであるか分かります。その情報は、繰り返される処理の中でよく利用されます。
これは一般にforループ、と言われるものの説明です。
……。
え〜と、上の説明もベースはC言語のもの、ですね。"{"と"}"で囲まれる部分がforループのブロックでその中の命令が逐次処理で繰り返されます。
これも実際、4つの動的言語で見てみましょう。
Pythonのforループ
for i in range(m, n + 1):
命令文1
命令文2
・・・
・・・
命令文x
Pythonのforループは上の説明と一ヶ所だけ食い違っています。
それは、
変数iの値がnになるまで繰り返し
と言う部分で、
range
による指定で「n回目まで」を目論んでいるんだったら「n + 1」と記述しなければならない、と言う事です。これはここでは端折りますがrange
関数の性質に由来します。その他の特徴としては、
for
と言うキーワードも「これからループ用のブロックが記述されますよ」と言うサインとして行末にコロン(:)が必要な事、そしてそのブロック内の命令群はfor
の位置より「一段深く」インデントを噛まさなければならない、と言う事です(これもIDLEが勝手にやってくれますが)。従って、
変数iの値がnより大きくなれば、括弧内の命令文は実行されずに制御はこの後に書かれている命令文に移ります。
の「この後に書かれている命令文」は
for
の位置と行頭が揃ってなければなりません。具体的に見ると次のような事です。
for i in range(m, n + 1):
命令文1
命令文2
・・・
・・・
命令文x
命令文y # ここはforループ外
上の例で見ると命令文yは
for
ループブロック内のインデントと行頭が揃ってません。従って、これはPythonにより「ループ内命令」とは解釈されずに、「for
ループが終わった後に」実行される命令となります。なお、Pythonでは
#
から行末までは「コメント」として解釈されて、実行には関係が無くなります。書いたコードにメモを記入しておく為にこの「コメント」を積極的に利用しましょう。このような「コメント」が可読性を上げる鍵になります。Rubyのforループ
for i in m..n
命令文1
命令文2
・・・
・・・
命令文x
end
Rubyの
for
ループの方が素直かもしれません。これは通大のテキストの通り、の動作をします。また、for
ループの終わりもend
で明示的に閉じなければならない、と言うのも分岐の書き方と同じです。このように、Rubyは大変整合性が取れています。
なお、RubyのコメントもPythonと同じ作法で、
#
から行末まではコメントとしてRubyに無視されるようになっています。Schemeのforループ
Schemeには
for
ループはありません。なお、Schemeのコメントはセミコロン(
;
)から行末まで、となっています。Rのforループ
for (i in m:n) {
命令文1
命令文2
・・・
・・・
命令文x
}
形式的には通大のテキストの記述に一番一致しそうです。ただし、Rの
for
ループはC言語のそれ、とも違います。恐らく事実上、この構文はRubyのものに一番近いでしょう。なお、RのコメントもPython、Rubyと同様、
#
から行末までインタプリタに無視される形となっています。
繰り返しの回数が前もって分からない場合は、反復を終了するためのなんらかの判断を必要とします。分岐処理と同様に、条件式等で記述される命題を用いて、次のように表現することにします。
(命題)である限り次を繰り返す
{
- 命令文1
- 命令文2
- ・・・
- ・・・
- 命令文x
}
これにより、まず(命題)が真か偽を調べて、真であれば"{"と"}"で囲まれた一連の命令文を実行します。命令文xの実行が終了すると、次に、また(命題)が真か偽か調べ、真であれば括弧内の命令文を実行します。命題が偽になった時点で制御は、この後に書かれている命令文に移ります。
このかたちの反復は、(命題)が最初から、偽であれば括弧内の命令文は一度も実行されません。また、(命題)が常に真であれば、永久的に括弧内の命令を順に実行するだけで、あとの命令文が存在したとしても、それが実行されることはありません。このことをよく無限ループに陥るといいます。
これは一般にwhileループ、と言われるものの説明です。
これも通大のテキストでは形式をC言語から借りてきています、が、割にwhileは分かりやすく、似たような構文を持っている言語が多いようです。
では見てみましょう。
Pythonのwhileループ
while 命題:
命令文1
命令文2
・・・
・・・
命令文x
これもPythonらしく、インデントの法則は一致しています。
while
ブロック内のインデントは一段深くなり、while
の行末はコロン(:
)が必ず要り用です。また、
while
を抜けた後の命令文のインデントは一段浅くなるのもfor
ループと同様です。
while 命題:
命令文1
命令文2
・・・
・・・
命令文x
命令文y # ここはwhileループ外
Rubyのwhileループ
while 命題
命令文1
命令文2
・・・
・・・
命令文x
end
これも形式的には通大のテキストやPythonと同じですね。Rubyらしく
while
ブロックの後には明示的にend
で閉じる必要があります。Schemeのwhileループ
Schemeには公式には
while
ループはありません(持っている実装もありますが、非公式なんでここでは取り上げません)。Rのwhileループ
while (命題) {
命令文1
命令文2
・・・
・・・
命令文x
}
これも形式的には通大のテキスト、そして構文的にはC言語そっくりです。
1番目の反復のかたちは、実は2番目の反復のかたちを用いて表現することができます。すなわち、
- i←m
(i≦n)である限り次をくりかえす
{
- 命令文1
- 命令文2
- ・・・
- ・・・
- 命令文x
- i←i + 1
}
と書けば、これは1番目の反復処理とまったく同じことを、コンピュータに指示したことになります。
反復処理のなかに一度無条件で一連の命令文を実行した後で、それらをある条件が満足されるまでさらに繰り返すものがあります。ここではその形の反復処理の説明は省略することにします。
これは良くある練習問題だと思います。
for
ループをwhile
ループに書き直したり、while
ループをfor
ループに書き直したり。まあ、その辺は各自自習してみてください。そして、これは「パズル」と言うより、問題を解くにあたって、どっちかが「より短くコードを記述出来る」場合があるから、なんです。だから殆どのプログラミング言語に最低でも
for
ループとwhile
ループの二つが搭載されているのです(ただし、Schemeは除きますが)。要するに一つは「適切な問題に適切なループを使おう」と言う練習なのです。もう一つ理論的な意味もあって、多くの言語では、実は
for
ループかwhile
ループのどちらかを「基本」として持っています(ただしやっぱりSchemeは除きます)。そして、プログラミング言語の内部で、実際にfor
ループをwhile
ループに「変換」したり、その逆をやってたりするわけです。「基本」を持ってて、理論的には「必要の無い」もう片方のループを実装する。これは単純にプログラムをする側の利便性の為、です。こう言う「本質的には必要が無いんだけど、敢えて利便性の為だけに組み込まれた(しかし実際は内部的には変換される)」構文を専門用語でシンタックス・シュガー(構文糖衣)と呼びます。そのシンタックス・シュガーを実感する練習でもあるわけ、ですね。ところで、Schemeには
for
ループもwhile
ループも存在しません。代わりに上の「変換の約束事」に良く似たdo
ループ、と言われるものを持っています。ここではそれを軽く紹介しておきましょう。
Schemeのdoループ
(do ((i m (+ i 1))) ;最初にiにmを代入してiを1づつ増やす
((< i n) (命令文y)) ;iがnを越えたらループを脱出する
(命令文1) ;ループ内ではこれら命令を逐次実行
(命令文2)
(・・・)
(・・・)
(命令文x))
これを見ると、上の
for
ループ←→while
ループ間の変換の要素が全て入ってるのが分かると思います。が、鬼のような読みづらさ、です。そして、実際、Schemeユーザーはこの
do
ループが大っ嫌いで、殆ど使いません。しかもこれもシンタックス・シュガーなのです。では、
for
ループもwhile
ループも無しでSchemeではどうやってループを実現しているのか?その秘密はおいおい分かってくるでしょう。そして結論から言えば、ここで紹介した4つの動的言語は全てループ構文無しでループを書けちゃうのです。
従って、ここで解説したループに関する通大テキストの読解は、ある意味全て無意味になります(笑)。
いままで見てきた逐次、分岐、反復を使って命令文の実行の順序を制御します。コンピュータは、まったく融通がききませんから命令文の順序を一つ間違えただけでも正しい結果を得ることはできません。プログラムを作成するとき、手順、段取りの順序を、一分の隙もなく、正確に指定しなければなりません。
<演習問題>
100点満点として、
- A 80以上
- B 70以上80未満
- C 60以上70未満
- D 60未満
のように、成績をつける処理の流れを記述しなさい。
Pythonでの回答例
一つのやり方としては、今までの制御構造の流れを用いて次のように記述する方法である。
if x <= 80:
print "A"
else:
if x <= 70:
print "B"
else:
if x <= 60:
print "C"
else:
print "D"
このように、
if
〜else
の構文は入れ子(ネスト)に出来、インデントを読んでいくと「どんどん深くなっていく」のが分かるだろう。これが一つの解答法、である。しかし、一般的にプログラマはあまりにも深くネストされたプログラムを好まない。出来れば同じような制御は同じようなインデントレベルに揃えたい。これも可動性を高める為、である。
こう言う場合は、Pythonでは
if
〜elif
〜else
と言う形式を用いる。
if x <= 80:
print "A"
elif x <= 70:
print "B"
elif x <= 60:
print "C"
else:
print "D"
これならインデントのネストはそんなに深くならない。
なお、問題文には「◯◯以上、××未満」と言う条件が付加されているのに、ソースコードでは「未満」は反映されていない。何故その必要が無いのか、と言うのも「逐次実行」の性質による。
例えば、点数が75点だったとして、当然一番最初にチェックされるのは「80点以上かどうか」である。ここで「偽」を喰らうと次の時点で「70点以上かどうか」をチェックされるわけだが、その時は既に「最初のテストをクリアしてない」ので80点未満なのは自明となる。従って、こう言う「上から順に実行される」コンピュータの性質では命題をパスしたかしないか、で後続の処理が施される為、それ以上考える必要が無い場合があるのだ。
これが逐次実行の美味しい性質なのである。
Rubyでの回答例
一つのやり方としては、今までの制御構造の流れを用いて次のように記述する方法である。
if x <= 80
puts "A"
else
if x <= 70
puts "B"
else
if x <= 60
puts "C"
else
puts "D"
end
end
end
このように、
if
〜else
の構文は入れ子(ネスト)に出来、インデントに従って読んでいくと「どんどん深くなっていく」のが分かるだろう。これが一つの解答法、である。しかし、一般的にプログラマはあまりにも深くネストされたプログラムを好まない。出来れば同じような制御は同じような字下げのレベルに揃えたい。これも可動性を高める為、である。
こう言う場合は、Rubyでは
if
〜elsif
〜else
と言う形式を用いる。
if x <= 80
puts "A"
elsif x <= 70
puts "B"
elsif x <= 60
puts "C"
else
puts "D"
end
これならインデントのネストはそんなに深くならないし、特にRubyの場合、
if
〜else
の制御で一つend
が必要になるので、最初のコードだと最後がend
だらけになってしまってたが、if
〜elsif
〜else
だと一つの制御構造なので、end
は一つだけ、に抑えられる。なお、問題文には「◯◯以上、××未満」と言う条件が付加されているのに、ソースコードでは「未満」は反映されていない。何故その必要が無いのか、と言うのも「逐次実行」の性質による。
例えば、点数が75点だったとして、当然一番最初にチェックされるのは「80点以上かどうか」である。ここで「偽」を喰らうと次の時点で「70点以上かどうか」をチェックされるわけだが、その時は既に「最初のテストをクリアしてない」ので80点未満なのは自明となる。従って、こう言う「上から順に実行される」コンピュータの性質では命題をパスしたかしないか、で後続の処理が施される為、それ以上考える必要が無い場合があるのだ。
これが逐次実行の美味しい性質なのである。
Schemeでの回答例
一つのやり方としては、今までの制御構造の流れを用いて次のように記述する方法である。
(if (<= x 80)
'A
(if (<= x 70)
'B
(if (<= x 60)
'C
'D)))
このように、Schemeの構文は入れ子(ネスト)に出来、インデントを読んでいくと「どんどん深くなっていく」のが分かるだろう。これが一つの解答法、である。
Schemeは「入れ子で書く」プログラミング言語ではあるが、出来ればインデントレベルは揃えたい。これも可動性を高める為、である。また
if
、if
、if
も数が多すぎて目障りである。こう言う場合は、Schemeでは
cond
〜else
と言う形式を用いる。
(cond ((<= x 80) 'A)
((<= x 70) 'B)
((<= x 60) 'C)
(else 'D))
これならインデントも深くならないし、見た目もカッキリとしてシンプルである。
なお、問題文には「◯◯以上、××未満」と言う条件が付加されているのに、ソースコードでは「未満」は反映されていない。何故その必要が無いのか、と言うのも「逐次実行」の性質による。
例えば、点数が75点だったとして、当然一番最初にチェックされるのは「80点以上かどうか」である。ここで「偽」を喰らうと次の時点で「70点以上かどうか」をチェックされるわけだが、その時は既に「最初のテストをクリアしてない」ので80点未満なのは自明となる。従って、こう言う「上から順に実行される」コンピュータの性質では命題をパスしたかしないか、で後続の処理が施される為、それ以上考える必要が無い場合があるのだ。
これが逐次実行の美味しい性質なのである。
Rでの回答例
一つのやり方としては、今までの制御構造の流れを用いて次のように記述する方法である。
if (x <= 80) {
print("A")
}
else {
if (x <= 70) {
print("B")
}
else {
if (x <= 60) {
print("C")
}
else {
print("D")
}
}
}
このように、
if
〜else
の構文は入れ子(ネスト)に出来、インデントを読んでいくと「どんどん深くなっていく」のが分かるだろう。これが一つの解答法、である。しかし、一般的にプログラマはあまりにも深くネストされたインデントを好まない。出来れば同じような制御は同じようなインデントレベルに揃えたい。これも可動性を高める為、である。
こう言う場合は、Rでは
if
〜else if
〜else
と言う形式を用いる。これもC言語の形式に準じている。
if (x <= 80) {
print("A")
}
else if (x <= 70) {
print("B")
}
else if (x <= 60) {
print("C")
}
else {
print ("D")
}
これならインデントのネストはそんなに深くならない。
なお、問題文には「◯◯以上、××未満」と言う条件が付加されているのに、ソースコードでは「未満」は反映されていない。何故その必要が無いのか、と言うのも「逐次実行」の性質による。
例えば、点数が75点だったとして、当然一番最初にチェックされるのは「80点以上かどうか」である。ここで「偽」を喰らうと次の時点で「70点以上かどうか」をチェックされるわけだが、その時は既に「最初のテストをクリアしてない」ので80点未満なのは自明となる。従って、こう言う「上から順に実行される」コンピュータの性質では命題をパスしたかしないか、で後続の処理が施される為、それ以上考える必要が無い場合があるのだ。
これが逐次実行の美味しい性質なのである。
0 コメント:
コメントを投稿