yamicha.com's Blog - Presented by yamicha.com
Blog yamicha.com's Blog - 2017/11 の記事
[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]

yamicha.com's Blog
 諸事情により、現在更新休止中。ご了承ください。もし今後ブログを再開することがあるとすれば、その際にはこのブログスクリプトではなく、新しく開発したものによるかもしれません。
 当ブログ管理者についてはこちらをご参照。
開発魔法(737)
社会問題(733)
お知らせ(11)
質問・バトン回答(15)
ゲスト出演(8)
経済・知的財産(150)
ゲーム開発(182)
[Ada] 勝手に補足
- Note
- 金配りの次の一手


- Endless Ultimate Diary
- 銃世界

漢字バトン
- うるる雑記帳
- 漢字接力棒

ツキアイゲノムバトン
- ブログ@うにうに画像倉庫
- あぶ内閣

縺イ縺セ縺、縺カ縺励ヰ繝医Φ
- 月夜のボヤキ
- 騎士サーラバトン
パスワードを使う
名無し (2012/02/27)


開発者解放裁判
yamicha.com (2010/03/14)
Winnyに関しては、私も「純白」とまでは考えておりませんし、使用し..

開発者解放裁判
通りすがり (2010/03/08)
winnyに関しては「ダウンロードソフト板」なんてところを拠点に開発..

新型インフルエンザの恐怖
いげ太 (2009/11/03)
> C#などの「int Some(int , int)」は、F#では「(int * int) ->..

時効に関する思考
yamicha.com (2009/08/31)
>いげ太さんコメントありがとうございます。手元にドキュメントが少..
Homepage
Blog Top
Normal View
List View
Search
Calendar
Comment List
Trackback List
Blog RSS
Send Trackback
Phone Mode
Administrator
yamicha.com
Blog
るううるる。
Source
法令データ提供システム
FindLaw
Development
Java2 Platform SE 6
Java EE 6 API
MySQL Developer Zone
PHP Reference
MSDN Library
Ada Reference Manual
Objective Caml
Python Documentation
Erlang
Prolog Documents
カテゴリ表示
 カテゴリ 経済・知的財産 に当てはまるもののみを表示します。

 存在する記事 150 件の中から 16-20 件を表示しています。
金配り
2008/11/04(Tue)05:05:59
 公明党が福田氏に対して強行に実行を主張していた「定額減税」。当初は自民党も冷ややかな目で見ており、実行するにしても規模をできるだけ小さくしようとしていたようですが、麻生内閣に代わってからは制御不能な怪物と化してしまいます。選挙がまずいと見るや、自民党までもが大規模な定額減税を主張し始め、さらに減税では手続きが煩雑かつ住民税・所得税免除者の救済にならないということで、総額2兆円を国民全員に配るなどと言い始めたのです。
 この金配り策はもう既定路線で、どうあがいても実行されるのかもしれません。しかし、今からでも遅くはありません。金配りなどというバカげたバラマキ無駄遣い策は一刻も早く取り下げ、もう2度と言い出さないことを国民に確約すべきです。せっかくの2兆円もの財源を金配りに使うなどという行為は、景気対策や福祉に使えるはずの特別収入をドブに捨てるも等しい行為です。何がどうあっても絶対にやめるべきです。
 いくら選挙が厳しいからといって、このようなくだらないバラマキを推進している自民党の人間には強い驚愕と失望を覚えざるを得ません。自民党に限らず、政治家の一部には議員にふさわしくない人間がいることは承知していますが、議員にふさわしくないばかりか、頭のおかしい人間が政権与党にいるのではたまりません。いくら選挙目当てであっても、このような狂った案を主張するなど、頭がまともならまずあり得ないことです。
 そもそも「埋蔵金」は国庫に属するもので、企業でいう特別収益です。これはあくまで国のもの、すなわち国民のものであって、政党が自身の選挙対策として使用してよいものではありません。特定の政党が自分の選挙のためだけに、国庫の金を横領して選挙対策に使用するも同然の行為を行おうとしているにもかかわらず、党内からは目立った反対の声は出ていないところに、自民党の末期を感じざるを得ません。おそらく異論はくすぶっているものの、誰も正直に言い出せないという状況なのでしょうが、いざとなったら他党に亡命する覚悟ででも苦言を呈する人間はいないのでしょうか。
 しかも、その経済効果はせいぜいGDPで0.1%と見積もられています。日本の近年のGDPが550兆円前後ですから、0.1%といえば5000億円程度でしょうか。2兆円も金配りをしておいてこれでは、極端に言えば穴を掘って埋めるだけの公共事業を2兆円分行った方がまだマシです。下手をすると穴を掘って埋めるより無駄な策といえるでしょう。公共事業や農業保障は時に「バラマキ」と批判されますが、いずれもある程度は必要不可欠なもので、実施にはそれなりの理由があります。しかし、この金配りは理由も何もあったものではなく、バラマキ以下としか表現しようがありません。
 麻生氏は経済状況を理由に解散を先延ばしし、果ては金配りを正当化していますが、このようなペテンにかかる人間はそうそういるものではありません。選挙が厳しいからといって、経済など適当な理由をつけて、自己利益のためだけに解散を先延ばしした挙句、金配りなどと言い出しているに過ぎません。本気で経済の立て直しこそまず必要と考えているのなら、金配りのような無駄な愚策を実行しようとするわけがないのです。
 そもそも金融危機は持続する可能性があり、いずれ解散も行わなければならないのですから、本当に経済のことを深く考えている人であれば、金配りなど最初から行わず、与野党で応急処置的な対策法のみを急いで成立させた後、すぐに解散して「経済対策選挙」を行うでしょう。埋蔵金の使い道はその選挙で争えば良いのです。これだけのことができる内閣であれば、応急処置を実現した上に11月中には選挙となっていたでしょう。先が見えないにもかかわらず、今よりも大きな危機に直面した状態で解散しなければならないリスクを犯してまで解散を先延ばしし、これから財源が必要かもしれないのにせっかくの埋蔵金を使って金を配り、緊急の対策が必要な状況にありながら、ずるずると解散を先延ばしするだけでろくな対策は打たない内閣が、「経済状況を考えて解散しない」などとは、一体どこから出てきた言葉でしょうか。これから危機の到来が予想されるのなら、なおさら難局を乗り切る政党や政策を選べるようにすべきです。
 また、もし解散を先延ばしするにしても、何が何でも金配りを行う前に解散すべきです。金配りは何の役にも立たない愚策ですが、このままでは国民に何の選択権もないまま実行されてしまい、2兆円もの財源がドブに捨てられてしまいます。2兆円ある状態で経済対策をするのと、すでにドブに捨てられた後で対策するのでは、大きな差があります。経済状況が危機的で、税収も減少が予想され、不況となれば安易に増税もできない状況下で、さらに2兆円をゴミ箱行きにするのであれば、選挙でその使い道を争うべきです。その上で、自民党は金配りを公約に盛り込んで主張すればよろしいでしょう。これで自民党が勝利し、2兆円が配られるのであれば、それは国民の選択ですからやむを得ません。
 国民は麻生氏が考えているほどバカではありません。少なくとも私はそう信じます。金配りなど言い出しても何の利益もないのですから、このようなバカげた案は一刻も早く取り下げるか、公約として選挙後に行うようにすべきでしょう。2兆円をドブに捨てる前に、使い道を国民の決定にゆだねるべきです。また、麻生氏が経済状況を考えて解散を先延ばししているのではないことは、上で述べた通り明らかなのですから、解散もできるだけ早期に行うべきです。麻生氏は「決断力」をアピールする作戦に出ているようですが、自己都合でジリジリと解散を引き伸ばす姿に決断力は見えません。この羊頭狗肉ぶりといい、金配りといい、解散を先延ばしして行うのは墓穴堀りばかりです。
 それでも解散を拒むなら、それはそれで結構です。しかし、金配りだけは絶対に選挙前に行ってはいけません。このような策で支持が上向くとは考えられませんし、2兆円をドブに捨てる前に国民の審判を仰ぐ必要があります。何がどうあっても絶対に、金配りの前に解散するか、金配りを取り下げるべきです。

 Ada 83は当時としては非常に先進的な言語で、最近の多くの言語の機能を先取りしています。Ada 95でオブジェクト指向関連の機能が導入されたとはいえ、Adaの原型は83の時点で完成されていたといえるでしょう。(少なくとも当初は)Cとほぼ完全な互換性を有してはいるものの、ほとんど別物になってしまったC++とは違い、Ada 95はあくまで83の拡張の範囲内に位置しています。
 Cでグローバル関数があふれかえっていた時代に「パッケージ」を導入したのも斬新ですし、例外などの様々な機構も備えています。しかし何よりすごいのは、何といってもジェネリック機構の存在でしょう。C++のテンプレート、Javaのジェネリックス、C#のジェネリックはすべてこれの類型です。テンプレート機構を活用したライブラリであるSTLの登場が90年代後半、C#が2000年代、Javaに至っては最近になってようやく導入されたような機構が、83年時点の規格で使えてしまうのです。
 とはいえ、AdaのジェネリックはJavaやC#ほどお手軽なものではなく、他よりも少々理解が難しくなっています。上記のいずれの言語も型の後に角カッコ(余談ながら、Dの場合は丸カッコ)をつけてジェネリック型を表現するのですが、Adaでは違います。ジェネリック型を割り当てていない関数・プロシージャ・パッケージはそのままでは使用できず、型を割り当てた新しい関数・プロシージャ・パッケージを作ることでそれを実現するのです。C++に例えれば、typedefが強制されているといったところでしょうか。C#ならデリゲートの作り方に近いです。
 このように書いても分かりづらいばかりですが、「百聞は一見にしかず」です。ジェネリックは関数・プロシージャ・パッケージのいずれかに対して使用することができ、いずれも型宣言に対して記述します(すなわち、package body及びその中身に対しては書かない)。ここではプロシージャに使用してみます。おそらくC++のテンプレートの解説などで使い古されているSwapの例です。
with Ada.Text_IO , Ada.Integer_Text_IO , Ada.Strings.Unbounded;
use Ada.Text_IO , Ada.Integer_Text_IO , Ada.Strings.Unbounded;

procedure Blog is
--	まずパッケージを作成
	package Swap_Package is
--		ジェネリックプロシージャを宣言
--		C++ でいうところの template<class Swap_Type> と同じ
		generic
			type Swap_Type is private;
		procedure Swap(a , b : in out Swap_Type);
	end Swap_Package;

--	パッケージの本体を記述
	package body Swap_Package is
		procedure Swap(a , b : in out Swap_Type) is
			c : Swap_Type;
			begin
				c := a;
				a := b;
				b := c;
		end Swap;
	end Swap_Package;

--	use するか、Swap_Package.Swap と書くか、renames するかはお好みで
	use Swap_Package;

--	プロシージャの実体を作成
	procedure Int_Swap is new Swap(Swap_Type => Integer);

	a , b : Integer;
	begin
		a := 10;
		b := 20;
		Int_Swap(a , b);
		Put(a);
		Put(b);
end Blog;
 これがAdaのジェネリックの基本です。パッケージ、関数、プロシージャのいずれの場合でも、もともとの名前を使用するのではなく、型を与えた実体を作成します。型は名前とセットにして与えても、順番に並べて与えても構いません。上記の場合なら
procedure Int_Swap is new Swap(Swap_Type => Integer);
procedure Int_Swap is new Swap(Integer);
 この両方が使用できます。
 型指定の方法にはいくつかのバリエーションがあり、特定の型のみを受け入れることができます。例えば上記プログラムの
type Swap_Type is private;
 このような記述は、limited以外のすべての型を受け入れてくれます。ただし、使用する型は実体のある型でなければなりません。例えばIntegerやString(1..10)は実体のある型ですが、Stringは実体のない型です。変数を作れるか否かが目安になります。実体のない型は、変数を作成するには情報が不足しているため、そのままでは使用できません。
-- 実体型
var : Integer;
var : String(1..10);

-- 実体のない型
var : String;	-- エラー
 また、ここが少々ややこしいところなのですが、limitedを含む実体型を受け入れたいなら
type Type_Name is limited private;
 このように書かなければなりません。この型はlimitedでも非limitedでも受け入れてくれますが、この型に対する代入と比較は禁止されます。ジェネリック関数・プロシージャ・パッケージの中でこの型をlimitedとして使用するわけですから、実際に与える型はlimitedより緩ければ何でも構わないのです。なお、先ほどのSwapプロシージャは代入を行っているため、Swap_Typeをlimited privateにすると動作しません。
 それ以外にも、
type Some_Type is (<>);
 これは分散型に限る記述です。Integerなど任意のものを取れますが、配列やレコードは合成型であるため禁止されます。仮に先のSwap_Typeが(<>)指定されていたら、
type Five_Char is new String(1..5);
procedure Str_Swap is new Swap(Swap_Type => Five_Char);
 このようなコードは書けません。String(1..5)はarray(1..5) of Characterであり、分散型ではないためです。
 ここまではいずれも実体型のみを取るものでしたが、次のように記述すると実体のない型も取ることができます
-- 実体のない型も取れる記述
type Swap_Type(<>) is private;

-- 他の指定と組み合わせてもよい
type Swap_Type(<>) is limited private;
type Swap_Type(<>) is (<>);
 1番目の指定では、limited以外のあらゆる型が許可されます。2番目の指定では、それに加えてlimited型も許可されます。いずれの場合も実体型とそうでない型の両方が取れます。
 その代わり、当然ながら型の使用には制限がつきます。実体でない型が渡される可能性がある以上、この型を使って変数を作成してはいけません。Stringやtype Some is new array(<>) of Integerなどといった型が渡されない保証はないのです。個数すら分からないのですから、これらから変数を作成できないのは言うまでもありません。
 特定のtagged record型の継承型のみを取る記法もあります。
type Some is new Some_Record with private;
 この型はSome_Recordの継承型でなくてはなりません。なお、上記ジェネリックでは必ずSome_Recordの継承型が渡されることが判明しているため、このジェネリック型からはSome_Recordの範囲のフィールドにアクセスできます。
with Ada.Text_IO;
use Ada.Text_IO;

procedure Blog is
	package Test_Package is
--		A から B を継承するが、C は別個のレコード
		type A is tagged null record;
		type B is new A with null record;
		type C is tagged null record;

--		A の継承レコードのみを取るジェネリック
		generic
			type A_Type is new A with private;
		procedure Test(a : in A_Type);
	end Test_Package;

	package body Test_Package is
		procedure Test(a : in A_Type) is
			begin
				Put_Line("Test が呼び出されました。");
		end Test;
	end Test_Package;

	use Test_Package;

	ai : A;
	bi : B;
	ci : C;

	procedure Test_A is new Test(A);
	procedure Test_B is new Test(B);
--	エラー : C は A の継承レコードではない
--	procedure Test_C is new Test(C);

	begin
		Test_A(ai);
		Test_B(bi);
--		Test_C(ci);
end Blog;
 一方、taggedではない型を取るものもあります。
type A_Type is new A;
 この場合、Aはtaggedであってはいけません。taggedが使えないため、withで機能を追加するわけにはいきませんが、Aを元にtype newで作ったレコードなら取れます。
with Ada.Text_IO;
use Ada.Text_IO;

procedure Blog is
	package Test_Package is
		type A is null record;
--		B は new A
		type B is new A;
		generic
			type A_Type is new A;
		procedure Test(a : in A_Type);
	end Test_Package;

	package body Test_Package is
		procedure Test(a : in A_Type) is
			begin
				Put_Line("Test が呼び出されました。");
		end Test;
	end Test_Package;

	use Test_Package;

	ai : A;
	bi : B;

	procedure Test_A is new Test(A);
	procedure Test_B is new Test(B);

	begin
		Test_A(ai);
		Test_B(bi);
end Blog;
 これ以外にも、必要な関数やプロシージャの存在を義務化してインタフェースの代わりにしたり、パッケージをジェネリックにしてSTL類似のライブラリを作るなど、非常に幅広い実装が可能となっており、Adaのジェネリックの本領発揮はここからなのですが、それはこの次としましょう。
カテゴリ [開発魔法][社会問題][経済・知的財産] [トラックバック 0][コメント 0]

期間限定バラマキ実施
2008/10/24(Fri)00:29:23
 福田氏が政権を投げ出したのは、民主党の追及や内閣のレームダック状態もさることながら、公明党に背後を撃たれたのも理由の1つであるといわれています。公明党は消費者保護や弱者救済の政策として「定額減税」を強硬に主張しましたが、自民党は決してこれに協力的ではなく、福田内閣は板ばさみになった格好です。
 ほどなくして福田氏は辞任し、出来レースの総裁選によって麻生氏が新総裁に就任しました。福田氏の辞任は状況の改善を狙ったものであり、とりあえずは仕切りなおしとなったため、私はてっきり定額減税の話も立ち消えになるものかと考えていました。ところが、定額減税は消滅するどころか、かなり大きな規模で実施される恐れが強まっているのです。
 自民党は当初、麻生氏の就任によって支持率を大幅に回復し、そのまま解散総選挙を行うつもりであったとみられます。自民党が出来レースの総裁選を演じたのも、世論の注目を集めるために他なりません。しかし、その浅はかな考えは見事に打ち砕かれます。このままでは選挙に敗北する可能性があるため、当初は定額減税に難色を示していたはずの自民党も、小手先の支持集めのために「相乗り」をしているというわけです。
 定額減税が単なるバラマキの愚策であることは、いまさら論じるまでもないでしょう。1度の定額減税で景気を回復しようとしたり、あるいは消費者のウケを狙おうなどというのは、言うなればタワーの上から紙幣をばら撒くのと全く変わらない行為です。景気回復目当てというより、支持率回復目当ての支出と表現する方が正しく、そのために国費を使用するのは全くの無駄です。いくら支持率が危険水域であるとはいえ、自民党が公明党の浅はかな案に乗ってしまったことにはあきれざるを得ません。
 ところが、問題はこれだけにとどまりませんでした。定額減税だけでも全く意味のないバラマキであるというのに、以前に触れた「高速道路の大幅値下げ」も与党の経済対策に盛り込まれる予定のようです。以前の段階では金子氏の独断である可能性もありましたが、これが与党の正式な対策に盛り込まれるとなれば、もはや担当大臣の独断ではありません。民主党も高速道路無料化を掲げていますが、こちらは先の記事で触れている通り、料金所がなくなるためにコストを低減でき、インターの作成も安価に可能になるというメリットがありますし、高速道路は無料化される約束の上で作られているため、それを遵守する意味では正当性があります。私は民主党案に100%賛成する気はありませんが、民主党案には一応のメリットや正当性があるにもかかわらず、与党案には新しいメリットが存在せず、単なるバラマキとしか言いようがないものとなっています。
 さらに驚くべきことに、この経済対策では中小企業に対する法人税時限減税案まで登場しています。「時限」の言葉通り、一時的に法人税を軽減するものです。対象は中小企業中心であるため、厄介な問題を無理な価格で下請けに押し付けたり、派遣などの非正規雇用を使い倒した上で、自分だけ過去最高益を上げるなどの行為により、世論の怒りを買っている大企業には恩恵が及びません。与党としては、これなら世論の支持を集められると考えているのでしょうか。
 しかしながら、こちらも定額減税と全く変わらないレベルのバラマキであることは言うまでもありません。いくら中小企業対象とはいえ、安易に法人税を下げる行為はすべきではありませんが、かといって時限減税などを行ったところでろくな効果は期待できません。資金繰り対策としてはあまりにもお粗末過ぎます。
 サブプライムローン破綻からの一連の問題が、今後の日本にどのような影響を及ぼすのかは、今のところははっきりしません。しかし、仮に日本の景気が大きなダメージを受け、零細企業が深刻な資金繰りの困難に直面するとして、果たして期間限定の法人税減税が役に立つのでしょうか。人件費抑制や非正規雇用のせいで消費は冷え込み、銀行は貸し渋りや貸しはがしに走り、下請けや孫請けの頂点に立つ大企業は更なる無理難題を押し付けてくるという状況において、法人税の時限減税は全くないよりはましでしょうが、実際には何の解決にもならないのです。
 このように、与党が検討しているいずれの案も、景気対策としてはお粗末過ぎるバラマキであると言わざるを得ません。与党がこれらの案を本気で有効と考えているのか、最初から景気対策など全く期待しておらず、選挙対策のためだけに行おうとしているのかは不明ですが、自民党はこれまで公明党の定額減税案に難色を示しており、選挙に敗北する可能性が高くなってきたところで同調したことを考えると、自民党はこれらの案が意味を持たないことを十分過ぎるほど承知しているのではないかと私は考えています。
 バラマキを行ったとしても、大半の財源を埋蔵金でまかなってしまえば、国債発行額を増やさないという面目は保たれます。しかも、これらのバラマキの多くは期間限定であるため、埋蔵金を使用する上では都合が良いのです。損益計算書の収支でいうなら、特別収益を特別損失で打ち消して帳尻を合わせた状態で、見かけ上は経常損益も全体の収支も今までと変わりません。
 このようなバラマキを計画しているようでは、政権が変わってバラマキ案も消滅する可能性が高まるばかりですが、自民党の総裁があの麻生氏であるだけに、与党が勝利する可能性も十分に残されています。与党が自らの勝利をまじめに考えているのなら、なおさらこのようなバラマキはやめるべきでしょぅ。

 Adaはオブジェクト指向言語です。メンバの隠蔽、演算子のオーバーロード、ジェネリックなど一通りの機能はサポートしている他、Ada 05からはインタフェースなどの新しい概念も導入されています。
 とはいえ、Adaも最初からオブジェクト指向として作られたのではありません。Ada 83が生まれた時代といえば、おおむねC++が生まれた辺りです。C++の普及以後、多くのオブジェクト指向言語はC++を手本として作られていますが、Adaの仕様策定時にC++を参考にすることはできませんし、仮に参考にすることができたとしても、当時はまだオブジェクト指向自体が実験的なスタイルとされていたはずです。いくら先見の明のAdaとはいえ、さすがにAda 83にはオブジェクト指向は導入されませんでした。
 ところが、昨今の言語の大半がこれをサポートしていることからも分かる通り、オブジェクト指向は非常に有用な概念でした。現存する機能に何か新しい機能を追加したくなったら、今までは既存のコードに手を加えるしかありませんでしたが、このような修正はうっかりするとバグの原因ともなり、デバッグも困難になる傾向にありました。しかし、これがオブジェクト指向であれば、コードを修正せずとも継承によって機能を追加できる上、仮にそれによって何らかのバグが生じたとしても、発生源はサブクラスでしかあり得ませんので、デバッグの手間も省けます。堅牢性をウリにするAdaがこれを見逃すはずがありません。
 かくしてAda 95には無理やりオブジェクト指向が導入されたのでありました。無理やりとはいっても、ちまたのオブジェクト指向言語と同等以上の機能は備えた本格的なもので、下手をするとC++より難解なほどです。さらにAda 05ではより自然な開発が可能となり、いくつかの新しい概念も導入されています。ライブラリ面でも、Adaが最初からジェネリックを備えていることを生かし、C++のSTLに相当するライブラリが導入されています。

 オブジェクト指向に入る前に、まずはAdaのパッケージについて。パッケージの概念も同時としては斬新で、これもAdaの先見の明といえるでしょう。パッケージ自体は単なるネームスペースで、特別な機能は持っていません。
 Adaのパッケージは2段階で定義しなければなりません。まずパッケージのメンバを定義しておいて、後でその本体を定義します。Cでプロトタイプ宣言と本体を別々に書くようなものです。
 ちなみに、C/C++のプロトタイプやJavaのインタフェースでは、
public interface Some{
	int method(int a , int b);
}

public class SomeClass implements Some{
	public int method(int first , int last){
		return first + last;
	}
}
 などのように実装先で変数名を好きな名前にしてしまうことができるのですが(C/C++では型だけ書けばよく、変数名を書く必要すらない)、Adaでは許されません。分かりやすい名前を使うようにしましょう。
with Ada.Text_IO;
use Ada.Text_IO;

procedure Blog is
--	まずパッケージの内容を定義
	package Say_Message is
		procedure Say_Multiply(a , b : in Integer);
	end Say_Message;

--	続いてパッケージの中身を定義
--	Integer'Image 属性が新しく登場しているが、
--	これは Java でいう toString と同じもの
	package body Say_Message is
		procedure Say_Multiply(a , b : in Integer) is
			begin
				Put_Line(Integer'Image(a) & " times " &
					Integer'Image(b) &
					" is " & Integer'Image(a * b));
		end Say_Multiply;
	end Say_Message;

--	ローカルのパッケージであっても、使用の際には use 宣言か、あるいは
--	Say_Message.Say_Multiply のようにパッケージ名を含む記述が必要
	use Say_Message;

	begin
		Say_Multiply(256 , 16);
end Blog;
 結果は次の通りです。
256 times  16 is  4096
 今回はローカルパッケージを使用しましたが、当然ながらローカルでないパッケージも作成できます。ただし、そのための記述は少々面倒です。C/C++ではプロトタイプをヘッダファイルに、実装をソースファイルに書いたりしますが、Adaでもそのようにしなければならないのです。定義を書くのが*.ads、実装を書くのが*.adbです。
 ここでは簡単に、ベクトル内積の演算でも行うパッケージを書いてみましょう。パッケージ名は何でも構いませんが、ここではLine_Mathとでもしておきます。Adaは大文字小文字を区別せず、ファイル名はパッケージ名と同じにすることが規則となっているため、定義はline_math.adsに、実装はline_math.adbに記述します。
-- line_math.ads
package Line_Math is
	function inner(a_x , a_y , b_x , b_y : in Float) return Float;
end Line_Math;

-- line_math.adb
package body Line_Math is
	function inner(a_x , a_y , b_x , b_y : in Float) return Float is
		begin
			return a_x * b_x + a_y * b_y;
	end inner;
end Line_Math;
 後は何らかのadbファイルからwithして使用するだけです。
with Ada.Text_IO , Ada.Float_Text_IO , Line_Math;
use Ada.Text_IO , Ada.Float_Text_IO;

procedure Blog is
	package lm renames Line_Math;

	begin
		Put(lm.inner(1.0 , 0.0 , 0.707 , 0.707));
end Blog;
 ここでpackage renamesなるものが登場しました。これは何らかのパッケージを別名で使用できるようにするもので、パッケージ名をそのまま書くと可読性が落ちて面倒ではあるものの、useしてしまうと名前がかぶる恐れがある場合に便利です。
 ところで、標準パッケージはAda.Text_IOのようにドット区切りの構造となっています。Javaではcom.yamichaのようにドメインを使用したものが普通に使用されますが、これを自作する方法はあるのでしょうか。
 ここではLine_Math.Vectorなるパッケージを作成してみましょう。まず用意しなければならないものは、line_math.adsです。パッケージの中身は空でも構いませんし、必要なら何か書いても構いません。もしline_math内に実装したいメンバがあるなら、line_math.adbを書くこともできます。
-- line_math.ads
package Line_Math is
end Line_Math;
 次に、line_math-vector.adsとline_math-vector.adbを作成します。中身は先に作成したものと同じです。見ての通りですが、ドット部分はファイル名ではハイフンになります
-- line_math-vector.ads
package Line_Math.Vector is
	function inner(a_x , a_y , b_x , b_y : in Float) return Float;
end Line_Math.Vector;

-- line_math-vector.adb
package body Line_Math.Vector is
	function inner(a_x , a_y , b_x , b_y : in Float) return Float is
		begin
			return a_x * b_x + a_y * b_y;
	end inner;
end Line_Math.Vector;
 使用方法も同じです。
with Ada.Text_IO , Ada.Float_Text_IO , Line_Math.Vector;
use Ada.Text_IO , Ada.Float_Text_IO;

procedure Blog is
	package v renames Line_Math.Vector;

	begin
		Put(v.inner(1.0 , 0.0 , 0.707 , 0.707));
end Blog;
 Javaなどに比べると面倒さが目立ちますが、これがAdaのスタイルです。Ada 83の仕様が策定された時代には、現代ほど高性能のコンピュータは存在せず、企業用コンピュータでしかコンパイラが動かなかったといいますから、コンパイル効率のために別々に書くようにしたのでしょうか。
 Javaのように定義と実装が分けられていない言語の場合、最初にメソッドなどの型情報を収集し、それから中身のコンパイルに移らなければ、何らかのパッケージなりメソッドなりが相互に依存していたり、階層が絡み合っているようなプログラムをコンパイルすることはできません。C/C++ではそのような作業を行わないため、プロトタイプ宣言の記述が必要になったり、時にはコンパイルの順序を気にしなければなりません。Adaのように定義と実装を分けておけば、コンパイルの順番を気にする必要はありませんし、型情報収集の負荷も抑制できるでしょう。
 パッケージはこの程度としまして、オブジェクト指向を。Adaのオブジェクト指向はレコードを使用します。この辺りはC++のクラスが構造体の拡張であるのと似ています(その上C++では、構造体にもクラスと同等の拡張がなされており、デフォルトのアクセス指定がpublicのクラスとして扱われています)。
 普通のレコードは次のように記述しました。
with Ada.Text_IO , Ada.Strings.Unbounded;
use Ada.Text_IO , Ada.Strings.Unbounded;

procedure Blog is
	type Person_Name is
		record
			first_name : Unbounded_String;
			last_name : Unbounded_String;
	end record;

	ada : Person_Name;

	begin
		ada.first_name := To_Unbounded_String("Ada");
		ada.last_name := To_Unbounded_String("Lovelace");
end Blog;
 さて、ここで個人の誕生年月日も入れたくなったとしましょう。オブジェクト指向らしく、Person_Nameを継承してデータを入れるようにしたいところです。
 レコードを継承するには、継承元のレコードがtagged指定されている必要があります。
type Some_Record is tagged
	record
		...
end record;
 tagged指定がなされていれば、そのレコードは継承可能です。継承は以下のようにして行えます。
with Ada.Text_IO , Ada.Strings.Unbounded;
use Ada.Text_IO , Ada.Strings.Unbounded;

procedure Blog is
--	元のレコード
	type Person_Name is tagged
		record
			first_name : Unbounded_String;
			last_name : Unbounded_String;
	end record;

	subtype Month is Integer range 1 .. 12;
	subtype Day is Integer range 1 .. 31;

--	継承したレコード
	type Person_Data is new Person_Name with
		record
			birth_year : Integer;
			birth_month : Month;
			birth_day : Day;
	end record;

	ada : Person_Data;

	begin
		ada.first_name := To_Unbounded_String("Ada");
		ada.last_name := To_Unbounded_String("Lovelace");
		ada.birth_year := 1815;
		ada.birth_month := 12;
		ada.birth_day := 10;
end Blog;
 ある意味でAdaらしい書き方といいましょうか。Javaなら「SubClass extends SuperClass」なのですが、Adaでは「type Sub_Record is new Super_Record with」です。既存の何らかの型を基本として、独自の新しい型を作成する際には
type Short is new Integer range -32768 .. 32767;
 などと書きましたが、レコードの継承の場合も同じというわけです。条件指定の部分が「with record ...」である辺りはAdaらしいといいましょうか。「new Integer range ...」の場合は「この範囲でIntegerを使用する新しい型」といった意味合いなのでしょうが、「new Old_Record with record ...」は「このレコード定義とともにOld_Recordを使用する新しい型」といったところでしょう。

 レコードにはlimitedなる指定が書かれることもあります。taggedではないレコードにもlimitedを書くことはできるため、taggedと特に関係があるわけではありませんが、taggedレコードを制限するものとして書かれる場合が多いため、ここで取り上げておきます。
 Adaではレコードの代入や比較を行うことができ、それらの実装はそれぞれ「レコードの全データをそのままコピー」「レコードのすべてのデータが一致したらtrue」となっています。最大公約数的な実装ですが、これがいかなる場合でも役に立つとは限りません。これの何が問題なのかは、経験豊富な開発者の方ならお分かりでしょうが、以下に少々小話を。
 例えば、ここに文字列なり配列なりを保持するクラスがあるとしましょう。JavaのArrayListのように、必要になったらバッファを増やしてくれるものです。無論、登録や削除の操作のたびに1つずつ配列要素数を増減させるのでは日が暮れてしまいますから、要素が足りなくなったら多めに配列を確保し、要素が余ってもすぐには解放しないものとします。ArrayListやBufferedStringの他、C++のSTLやC#のライブラリなど、ほとんどの可変長リストはこのように実装されています。
 あなたはこのクラスを使用し、aというインスタンスを作成しました。データを10個ほど登録したでしょうか。この場合の挙動はライブラリの実装にもよりますが、ここでは「最初の要素数は1個で、必要となるたびに倍になる」という実装であるとしましょう。すると、aには16個の要素が作られることになります。
インスタンス a 内のデータ :
length = 10;
datas = {"Ada" , "Scheme" , "OCaml" , "F#" , "Haskell" , "Common Lisp" , 
	"Python" , "COBOL" , "Erlang" , "FORTRAN" , (不明) , (不明) , 
	(不明) , (不明) , (不明) , (不明)}
 「(不明)」の部分には何が入っているか分かりません。この部分は使用されていないため、別に何が入っていても構わないのです。nullなり空白なりといったデータかもしれませんし、未初期化メモリの内容かもしれません。この部分を以前に使用しているのなら、前のデータが残っているかもしれません。
 ここでデータが必要なくなったあなたは、最初の3つ以外をすべて取り除いてしまいました。
インスタンス a 内のデータ :
length = 3;
datas = {"Ada" , "Scheme" , "OCaml" , (不明) , (不明) , (不明) , 
	(不明) , (不明) , (不明) , (不明) , (不明) , (不明) , 
	(不明) , (不明) , (不明) , (不明)}
 今度削除された(不明)部分には、おそらく前のデータが残っていることでしょう。このインスタンスaに格納されているデータは、あなたの目には「Ada , Scheme , OCaml」に見えますし、メソッドを使って取り出してみても実際にその通りなのですが、実際には違うのです。
 さて、あなたはbというインスタンスも作成しました。これには最初から3つのデータのみを登録しました。
インスタンス b 内のデータ :
length = 3;
datas = {"Ada" , "Scheme" , "OCaml" , (不明)}
 どちらのインスタンスでも、中身のデータは同じはずです。しかし、インスタンス同士を直接比較した場合、falseが返ってしまうのです。このカラクリはもうお分かりでしょう。
 代入に関しても同様です。よく分からない方は、なぜJavaではClonableをインプリメントしなければcloneメソッドが使えないのかを調べてみると良いかもしれません。
 このように、比較と代入には落とし穴があります。比較や代入の必要がない、あるいはそれらをさせたくないデータであることが分かっているなら、limited指定をつけておいた方が良いでしょう。アクセス指定にしてもそうですが、どちらでも構わなければ厳しい指定を選ぶのが基本です。

 継承可能なレコードとlimitedレコード、それにパッケージが作成可能になったところで、これ以上は次の機会に。tagged、limited、packageとも、オブジェクト指向を実装する上では極めて重要です。
カテゴリ [開発魔法][社会問題][経済・知的財産] [トラックバック 0][コメント 0]

リーマンの終焉
2008/09/18(Thu)03:32:24
 サブプライム問題のあおりを受け、何とリーマンとメリルリンチが再起不能に陥りました。サブプライムがいくら大問題であるといっても、「この世をば、我が世ぞと思う」状態にあった両社が倒れてしまうのですから、衝撃の大きさが分かるというものです。最終的にリーマンは破綻し、メリルリンチはバンク・オブ・アメリカに買収されました。
 リーマンといえばライブドアのニッポン放送買収資金を引き受けた会社です。あの買収劇自体が村上ファンドの仕組んだもので、夜間取引のトリックを指南したのも村上ファンドでした。結果、ライブドアは株を買い占めるもフジサンケイ乗っ取りに失敗、フジも痛手を負うこととなりました。結果、「漁夫の利」を手に入れたのが村上ファンドとリーマンでしたが、村上ファンドは自らのニッポン放送株を処分するためにこのような作戦を仕組んでおり、最終的に村上氏はインサイダー取引で逮捕されました。ライブドアもフジからある程度の譲歩を引き出すことができたようですが、堀江氏らの逮捕によってフジから提携契約を破棄されてしまい、今では過去の栄光も何もない状態にあります。結局、最も良い立場にいたのはリーマンということになりますが、そのリーマンも破綻してしまいました。
 問題の発端はサブプライムローンですが、これがまた非常に無茶な仕組みとなっており、破綻したのは必然にさえ見えます。サブプライムは社会的信用が低い人向けのローンとされており、回収できる確率が通常のローンより低いため、通常のローンより金利が高く設定されています。市場原理からすればまっとうな言い分なのですが、通常のローンを組めない人から高い金利を巻き上げるのですから、なおさら回収不能になる可能性は高くなります。
 こうしたローンの中には、初頭の数年度のみ条件が緩和されるものもあったといいます。この場合、最初はまともな条件であっても、数年後からは無理な条件となり、最後には破綻を招くことになります。その結果、家を買ったは良いものの、こうして無理な状態になり、家も取られてローンは残る、という最悪の状況が発生します。
 このような危ないローン契約が大量になされた上、住宅価格の上昇にも天井が見えてきたため、もはや物件を売却して貸付金を回収することも難しくなり、サブプライムローンの状況はいよいよ悪くなります。サブプライムローンの債権は典型的な高リスク・高リターン投資として商品化されているらしいのですが、これによってサブプライムの債権を組み込んだ金融商品もダメージを受け、それを運用していたファンドも大打撃をこうむるなど、経済全体に大きな影響を与え、今日の騒動に至ります。
 ともかく、この問題が米国その他の経済に与えた影響が非常に大きいことは、メリルリンチとリーマンを見ての通りです。このままでは大手の金融関連会社をつぶしかねません。そこで出てきたのが、日本でも「りそな」で有名な公的資金の注入案です。なお、りそなの公的資金注入の際には多くの反対意見が見られましたが、米国でもそれは同じです。大手会社がつぶれるとなると影響が非常に大きいため、それを未然に防止して混乱を避ける策の必要性も分かりますが、大手会社とはいえ私企業に公的資金を注入することに対する批判や、「つぶれるものはつぶした方が筋肉質になる」「救済頼みになりかねない」といった意見ももっともです。当初はリーマンにも公的資金の注入が検討されていたようですが、最終的には先の理由によって見送られたようです。
 リーマンへの公的資金注入見送りについては、米国政府にも苦悩がうかがわれる他、なぜか日本のマスコミの一部までもが批判的な主張をしていますが、これは「進むも地獄、戻るも地獄」の状況であることを念頭に置かなければなりません。資金を注入してもしなくても、それぞれ何らかの問題が発生してきます。注入しなければ「市場の混乱を招いた」「多数の関係企業に被害を与え、または破綻させた」と批判されますし、注入すれば「淘汰されるべき企業に税金を無駄に投入した」「ピンチの各社が支援頼みになってしまった」などの批判が出るでしょう。いずれにしても何らかの批判は回避できないのです。
 そのような意味では、安易に資金注入をしないとの判断は、国内外の市場に不安を与えた点についてはともかく、「支援頼み」にならないようにした点では妥当なところでしょう。一方で、米国政府が資金注入を絶対に拒否するわけではないことは、保険会社AIG(日本法人のグループ会社にアリコ、アメリカンホームなどが存在)への資金注入を見ても分かります。各社の影響力などを考慮し、難しい舵取りを迫られているようです。
 それにしても、まさかリーマンやメリルリンチ、AIGまでもが破綻または破綻寸前になるとは、時代の変革期ということでしょうか。

 自民党総裁選は麻生氏が勝利確実ということで、筋書きがすべて事前に決定されていたであろう興ざめの完全出来レースであることが分かりましたが、この緊急事態にあっても自民党はタガが緩みっぱなしなのか、早速失言が飛び出しています。太田氏の「じたばた騒いでいない」に加え、麻生氏まで「豪雨は岡崎でよかった」発言という有様です。
 失言の恐ろしいところは、普段考えていることが何気ないきっかけで口から出てしまうことに他なりません。どれほど美辞麗句を並べ立てて取り繕ったとしても、失言こそが本音なのです。よからぬたくらみを腹の中にしまっているような政治家に比べれば、失言でそれを表に出してくれる人の方がマシともいえますが、それにしても大変な「本音」です。
 実際、太田氏は以前に「やかましい」発言でひんしゅくを買っており、麻生氏も「アルツハイマー」発言が問題になりました。ましてや、今は自民党が存亡の危機に立たされているのですから、よからぬ発言の1つが命取りになりかねないことは承知しているはずです。もし低IQ選挙に持ち込むつもりであるなら、失言など大した問題にはならないのでしょうが、あまりに危機感が薄すぎると言わざるを得ません。
 特に太田氏は短期間に2度も食に関する失言をしていますが、この失言の内容を見る限り、どうも国民の安全を守るという意思が希薄に感じられます。特に「じたばた」発言などその極みで、確かにこの量では健康に被害はないのかもしれませんが、「健康に被害を与える可能性が低ければ、農薬やカビのついた米を問題にする必要がない」とはならないのです。致死量であれ無害であれ、基準に反するような行為は「じたばた騒ぐ」べき問題なのです。そもそも、今回の事故米問題によって健康被害が出なかった(と今のところ考えられている)のは、あくまで偶然であったことを忘れてはいけません。メタミドホスがギョーザ問題並みの濃度で付着していたり、カビが発がん性の毒を大量に持っていたりしたら、じたばたどころではない騒ぎになっていたでしょう。健康被害があるかないかは結果に過ぎません。食用にしてはならない米が食用に使われたことと、しかもそれを「じたばた騒いでない」と言い放つ政治家の感覚が問題なのです。
 麻生氏については、もはや軽々しすぎるというしかありません。都心から離れたところでちょっとした地震が発生し、塀の角が多少壊れた程度の被害で済んだのであれば、これを「都心でなくて良かった」と発言したとしても、不適切とはみなされないでしょう。ところが、この豪雨はそのような生易しいものではありません。地域にかなりの被害を及ぼし、痛ましいことに死者まで出ているのです。死者が出ているにもかかわらず「良かった」とは、いくら比較のために使った言葉であるとしても、適切であるとは到底考えられません。
 各政治家にここまで危機感がないのは、やはり総裁選が結果の決まった出来レースであり、しかも民主党を埋没させるためにあえて行われたお芝居だからでしょうか。

 COBOLには数種類のファイル編成方法とアクセス方法があり、それぞれ読み書きの仕様が異なることは以前までに取り上げました。しかし、COBOLは事務処理用の言語なのですから、単にファイルを作成できるだけでは困ります。レコードの修正や削除、追加などができなければ、事務処理用言語としては失格であると言わざるを得ません。
 当然のことながら、COBOLは修正・削除・追加のすべてをサポートしています。ところが、これは編成方法とアクセス方法によって非常に複雑に変化するため、一筋縄ではいきません。これらの組み合わせによっては、レコードが修正できなかったり、あるいは削除できなかったりします。
 これらを行うに当たって重要な点として、まずOPENにはINPUT、OUTPUT、I-O、EXTENDの4種類があり、それぞれ行える動作が違ってきます。INPUTは読み込み専用、OUTPUTは新しくファイルを作成する命令であるとして、重要なのは後の2つです。I-Oは読み書き可能な命令で、REWRITEによってレコードを更新したり、DELETEで削除することができます。あるいは新しいレコードを追加することも可能です。EXTENDはC言語でいう"a"であり、ファイル末尾にデータを追加するものです。ただし、EXTENDはファイル末尾にポインタを置いてデータを追加していくという関係上、ACCESS MODEがSEQUENTIALでなければなりません。RANDOMやDYNAMICのファイルにデータを追加するのであれば、まずファイルをI-Oで開いた後、新しいデータにユニークなRECORD KEYを割り当てて行うことになります。
 それでは、まずはDELETEから。DELETEは単にデータを除去する命令です。詳しくは後述しますが、DELETEはRELATIVE及びINDEXED編成にしか使用できません。ACCESS MODEの指定は何でも構いませんが、SEQUENTIALとRANDOM及びDYNAMICでは使い方が少し異なります。SEQUENTIALでは削除したいレコードをREADで頭出ししてからDELETEで削除し、RANDOMとDYNAMICではRECORD KEY変数に削除したいレコード値を代入し、次いでDELETEを呼び出します。RANDOM及びDYNAMICではDELETE中にINVALID KEY指定を入れることができ、指定されたレコードが見つからなかった場合の動作を定めることができます。
 まずはSEQUENTIALの例から。INSPECTなる命令が登場していますが、これは単に文字列処理の命令であり、ファイル処理には特に関係ありません。
IDENTIFICATION DIVISION.
	PROGRAM-ID. BLOG.

ENVIRONMENT DIVISION.
	INPUT-OUTPUT SECTION.
		FILE-CONTROL.
*			ORGANIZATION IS は RELATIVE か INDEXED
			SELECT FNAMES ASSIGN TO 'blog'
				ORGANIZATION IS RELATIVE
				ACCESS MODE IS SEQUENTIAL
				RECORD KEY IS DID
				FILE STATUS IS STAT.

DATA DIVISION.
	FILE SECTION.
		FD FNAMES.
			01 NAMES.
				03 DID PIC 9(4).
				03 DNAME PIC X(16).
	WORKING-STORAGE SECTION.
		01 STAT PIC XX VALUE '00'.
		01 STRLEN PIC 9(4).

PROCEDURE DIVISION.
	MAIN-PARAGRAPH.
*		データの書き込み
		OPEN OUTPUT FNAMES

		MOVE 1 TO DID
		MOVE 'Miranda' TO DNAME
		WRITE NAMES

		MOVE 2 TO DID
		MOVE 'Ada' TO DNAME
		WRITE NAMES

		MOVE 3 TO DID
		MOVE 'Pascal' TO DNAME
		WRITE NAMES

		MOVE 4 TO DID
		MOVE 'Haskell' TO DNAME
		WRITE NAMES

		MOVE 5 TO DID
		MOVE 'Erlang' TO DNAME
		WRITE NAMES

		CLOSE FNAMES

*		登録されたデータの DNAME に
*		S または s が1つも含まれていない場合は削除
		INITIALIZE STAT

		OPEN I-O FNAMES

		PERFORM UNTIL NOT STAT = '00'
			READ FNAMES
				AT END
					CONTINUE
				NOT AT END
					MOVE 0 TO STRLEN
					INSPECT DNAME TALLYING
						STRLEN FOR ALL 's' , 'S'

					IF STRLEN = 0
						DELETE FNAMES
					END-IF
			END-READ
		END-PERFORM

		CLOSE FNAMES

*		読み込み
		INITIALIZE STAT

		OPEN INPUT FNAMES

		PERFORM UNTIL NOT STAT = '00'
			READ FNAMES
				AT END
					CONTINUE
				NOT AT END
					DISPLAY DNAME
			END-READ
		END-PERFORM

		CLOSE FNAMES.

 この結果、PascalとHaskellのみが残ります。
 RANDOMまたはDYNAMICではRECORD KEYを使って削除ができます。指定されたRECORD KEY値のレコードが存在しない場合には、INVALID KEY部が実行されます。ここでは不要なINVALID KEYは省いてありますが、COBOL処理系によってはこれがなければコンパイルできなかったりするようです。また、これは例外処理のtry-catchを書くようなものですから、普段は極力書いた方が良いでしょう。
IDENTIFICATION DIVISION.
	PROGRAM-ID. BLOG.

ENVIRONMENT DIVISION.
	INPUT-OUTPUT SECTION.
		FILE-CONTROL.
			SELECT FNAMES ASSIGN TO 'blog'
				ORGANIZATION IS RELATIVE
				ACCESS MODE IS DYNAMIC
				RECORD KEY IS DID
				FILE STATUS IS STAT.

DATA DIVISION.
	FILE SECTION.
		FD FNAMES.
			01 NAMES.
				03 DID PIC 9(4).
				03 DNAME PIC X(16).
	WORKING-STORAGE SECTION.
		01 STAT PIC XX VALUE '00'.

PROCEDURE DIVISION.
	MAIN-PARAGRAPH.
*		データの書き込み
		OPEN OUTPUT FNAMES

		MOVE 1 TO DID
		MOVE 'Miranda' TO DNAME
		WRITE NAMES

		MOVE 2 TO DID
		MOVE 'Ada' TO DNAME
		WRITE NAMES

		MOVE 3 TO DID
		MOVE 'Pascal' TO DNAME
		WRITE NAMES

		MOVE 4 TO DID
		MOVE 'Haskell' TO DNAME
		WRITE NAMES

		MOVE 5 TO DID
		MOVE 'Erlang' TO DNAME
		WRITE NAMES

		CLOSE FNAMES

*		I-O モードで開く
		INITIALIZE STAT

		OPEN I-O FNAMES

*		DID = 3 を消してみる
		MOVE 3 TO DID
		DELETE FNAMES

*		DID = 5 も消してみる
		MOVE 5 TO DID
		DELETE FNAMES

*		INVALID KEY の動作確認
*		存在しないデータを消してみる
		MOVE 6 TO DID
		DELETE FNAMES
			INVALID KEY
				DISPLAY 'データがありません。'
		END-DELETE

		CLOSE FNAMES

*		読み込み
		INITIALIZE STAT

		OPEN INPUT FNAMES

		PERFORM UNTIL NOT STAT = '00'
			READ FNAMES NEXT RECORD
				AT END
					CONTINUE
				NOT AT END
					DISPLAY DNAME
			END-READ
		END-PERFORM

		CLOSE FNAMES.
 こちらはDIDが3と5のデータのみが削除されます。また、DID = 6のデータは存在しないため、INVALID KEYが呼ばれます。成功時のみ呼び出したいコードがあるなら、NOT INVALID KEYなるものも用意されています。
 次にREWRITEです。データの修正はこれで行います。SEQUENTIAL、RELATIVE、INDEXEDで使えますが、LINE SEQUENTIALでは使えません。こちらも使い方はDELETEとほとんど同じです。ACCESS MODEがSEQUENTIALなら、READで修正したいレコードを頭出しして修正してからREWRITEし、RANDOMやDYNAMICならRECORD KEYで修正したいレコードを指定します。
 全くDELETEと同じで面白みがありませんので、RANDOMまたはDYNAMICの場合の書き方のみ示します。また、REWRITEにもINVALID KEYを指定できますが、これまたDELETEと同じですので省略します。
IDENTIFICATION DIVISION.
	PROGRAM-ID. BLOG.

ENVIRONMENT DIVISION.
	INPUT-OUTPUT SECTION.
		FILE-CONTROL.
			SELECT FNAMES ASSIGN TO 'blog'
				ORGANIZATION IS RELATIVE
				ACCESS MODE IS DYNAMIC
				RECORD KEY IS DID
				FILE STATUS IS STAT.

DATA DIVISION.
	FILE SECTION.
		FD FNAMES.
			01 NAMES.
				03 DID PIC 9(4).
				03 DNAME PIC X(16).
				03 DFULL PIC X(40).
	WORKING-STORAGE SECTION.
		01 STAT PIC XX VALUE '00'.

PROCEDURE DIVISION.
	MAIN-PARAGRAPH.
*		データの書き込み
		OPEN OUTPUT FNAMES

		MOVE 1 TO DID
		MOVE 'COBOL' TO DNAME
		MOVE 'Common Business Oriented Language' TO DFULL
		WRITE NAMES

		MOVE 2 TO DID
		MOVE 'PHP' TO DNAME
		MOVE 'Personal Home Page' TO DFULL
		WRITE NAMES

		MOVE 3 TO DID
		MOVE 'ML' TO DNAME
		MOVE 'Meta Language' TO DFULL
		WRITE NAMES

		CLOSE FNAMES

*		I-O モードでの読み書き
		INITIALIZE STAT

		OPEN I-O FNAMES

*		DID = 2 を修正
*		まず DID に 2 を設定
		MOVE 2 TO DID

*		DID = 2 のデータを読み込む
		READ FNAMES

*		修正
		MOVE 'PHP Hypertext Preprocessor' TO DFULL
		REWRITE NAMES

		CLOSE FNAMES

*		読み込み
		INITIALIZE STAT

		OPEN INPUT FNAMES

		PERFORM UNTIL NOT STAT = '00'
			READ FNAMES NEXT RECORD
				AT END
					CONTINUE
				NOT AT END
					DISPLAY DFULL
			END-READ
		END-PERFORM

		CLOSE FNAMES.
 修正後のデータが出力されれば成功です。
 残るはOPEN EXTENDだけですが、これはもう説明の必要もないでしょう。
IDENTIFICATION DIVISION.
	PROGRAM-ID. BLOG.

ENVIRONMENT DIVISION.
	INPUT-OUTPUT SECTION.
		FILE-CONTROL.
			SELECT FNAMES ASSIGN TO 'blog'
				ORGANIZATION IS SEQUENTIAL
				ACCESS MODE IS SEQUENTIAL
				RECORD KEY IS DID
				FILE STATUS IS STAT.

DATA DIVISION.
	FILE SECTION.
		FD FNAMES.
			01 NAMES.
				03 DID PIC 9(4).
				03 DNAME PIC X(16).
	WORKING-STORAGE SECTION.
		01 STAT PIC XX VALUE '00'.

PROCEDURE DIVISION.
	MAIN-PARAGRAPH.
*		データの書き込み
		OPEN OUTPUT FNAMES

		MOVE 1 TO DID
		MOVE 'COBOL' TO DNAME
		WRITE NAMES

		CLOSE FNAMES

*		データの追加
		INITIALIZE STAT

		OPEN EXTEND FNAMES

		MOVE 2 TO DID
		MOVE 'C++' TO DNAME
		WRITE NAMES

		MOVE 3 TO DID
		MOVE 'OCaml' TO DNAME
		WRITE NAMES

		CLOSE FNAMES

*		読み込み
		INITIALIZE STAT

		OPEN INPUT FNAMES

		PERFORM UNTIL NOT STAT = '00'
			READ FNAMES NEXT RECORD
				AT END
					CONTINUE
				NOT AT END
					DISPLAY DNAME
			END-READ
		END-PERFORM

		CLOSE FNAMES.
 ただの追加です。ログを作るのには便利でしょうか。ORGANIZATIONはRELATIVEなどでも構いませんが、ACCESS MODEはSEQUENTIALでなくてはなりません。

 さて、これでファイルの修正も問題なし、と言いたいところですが、COBOLは手ごわい言語です。ORGANIZATIONとACCESS MODEの組み合わせによっては、操作が失敗してしまうのです。
 これを理解するには、まずファイルの構造に関する部分を理解しなくてはなりません。COBOLは事務処理用の言語ですから、何千何万のレコードを扱う可能性もあります。となると、ファイルの操作は手際よく行わなくてはなりません。
 メインフレームでファイルをどのように扱っているのかは知りませんが、ファイルを扱う上で低コストの操作は「データの書き換え」と「末尾へのデータの追加」でしょう。一方、「ファイルの先頭にデータを追加」などという操作は非常に高コストです。なぜなら、それ以後のデータ(例えば1万件のレコード)をすべて後ろに動かさなくてはならないのですから。配列操作と同等と考えれば分かりやすいでしょう。配列の場合、すでに10000個のデータが格納されているとして、その先頭に1つデータを格納したくなったら、データを1つ後ろにずらす操作を10000回しなければなりません。一方、末尾に登録するなら10001個目にデータを書き込むだけですし、先頭のデータを更新するのであれば、先頭にデータを書き込むだけです。
 何万件ものデータが登録されているかもしれないのに、登録・修正・削除のたびに後のデータすべてをずらしていては、事務処理どころではありません。つまり、COBOLでは後ろのデータを動かさなくてはならないような操作は禁止されていると考えることができます。これを踏まえて、編成やアクセスモードを考えてみます。

SEQUENTIAL
 REWRITEは許容されていますが、DELETEは使えません。DELETEのたびにファイルを切り詰めていては、先のルールに違反するためでしょう。また、ACCESS MODEにRANDOMやDYNAMICを指定することはできますが、実際にランダムアクセスはできません。最も単純な構造で、データは基本的にそのまま保持されますが、可変長配列だけはDEPENDING ON変数で指定した長さで保存されます。
 ただし、可変長配列のREWRITEには制限があります。ひとたびWRITEしてしまうと、もはや配列長を修正することはできないのです。これは「後ろのデータを動かしてはいけない」ルールを考えれば当然の仕様といえます。例えば可変長配列内の1つのデータが10バイトとして、長さが5であったのを6にすると、余分に10バイト分のデータが必要となりますので、確保するためには後ろのデータを10バイトずつずらさなくてはなりません。したがって、配列長は変更できないことになります。

LINE SEQUENTIAL
 この編成方式では、DELETEはおろかREWRITEすら禁止されています。LINE SEQUENTIALは末尾の空白文字を削除する仕様となっており、ファイル容量の点からは優れているのですが、レコードの長さ自体が可変長となってしまうため、単にREWRITEするだけでもレコードの長さが変わってしまう恐れがあります。したがって、データには全く修正を行うことができず、ログを書き出す程度しか使い道がありません。

RELATIVE
 ACCESS MODEがSEQUENTIALとそれ以外の場合では仕様が異なります。DELETEとREWRITEがサポートされています。RELATIVEは可変長配列であっても最大長を確保するため、容量の面ではあまりよろしくないのではありますが、そのために可変長配列をもREWRITEできるというメリットがあります。とはいえ、RELATIVEで可変長配列を使う意味はほとんどないのではありますが。DELETEの使用が可能ですが、その場でデータを消すのではルールに違反しますので、「削除フラグ」を使って削除をマークすることで、そのレコードが使われないようにしています。
 ACCESS MODEがSEQUENTIALの場合、レコードはデータを登録した順番に書き込まれていきます。データを修正・削除したり、OPEN EXTENDでデータを追加していくことも可能です。RANDOM及びDYNAMICの場合、データはRECORD KEYの順番にソートされています。しかし、ここで気になるのがルールとの兼ね合いです。例えばRECORD KEYが1のデータと3のデータがあったとして、このファイルに2のデータを書き込んだらどうなるのでしょうか。
 何とこのRELATIVE編成、3のデータを登録した時点で1と3の間に1レコード分の空白が用意されるのです。ここの空白に2のデータを登録すれば、ルールを破ることなくデータの登録が可能です。確かに有効な解決方法ではありますが、問題はここからです。最初からRECORD KEYの値が200などというデータを登録しようものなら、その前に199レコード分の空白ができてしまうのです。気をつけて使いましょう。なお、DELETEによって削除フラグがつけられたデータは、同じ番号のデータが登録されるまではその場に残り、同じ番号のデータが書き込まれる際には、そこに新しいデータが上書きされます。

INDEXED
 DELETEとREWRITEがサポートされています。しかし、可変長配列では長さの分だけしかデータを確保していないため、SEQUENTIAL同様にREWRITEで長さを変えることはできません。DELETEを実行すると、RELATIVE同様にレコードに削除フラグがつけられますが、INDEXEDはRELATIVEと違って索引を保持しているため、データを几帳面に並べる必要はありません。したがって、次に何らかのデータを登録すると、以前に削除した適当なレコードが再利用される場合があります。
 この索引のおかげでデータを番号順に並べなくても良いわけですが、これはつまり最初からRECORD KEYの値が200などというデータを登録しても、レコード199個分も無駄に確保する必要がないことを意味します。INDEXEDはとにかく索引さまさまです。

 ファイルの作成は用途に応じて計画的に行いましょう。追加・変更・削除の激しい「顧客」などといったファイルにLINE SEQUENTIALを使うと泣きを見ますし、ログを保持するのにINDEXEDを使うなどというのは無駄です。ログならむしろ、末尾の余分な空白を切り捨てて保存してくれるLINE SEQUENTIALを使うべきでしょう。SEQUENTIALはデータの変更の可能性がある順ファイル、あるいはサイズが固定となることが分かっているデータに有効ですし、RELATIVEはDELETEとREWRITE、ランダムアクセス機能を備えながら、INDEXEDよりファイル構造は単純ですし、索引データ保持の必要もないため、連番のデータに適しています。INDEXEDはRECORD KEYが飛び飛びのデータや、1度登録したら配列長を変えないことが分かっている可変長配列データに有利です。
カテゴリ [開発魔法][社会問題][経済・知的財産] [トラックバック 0][コメント 0]

ポイ捨て
2008/09/05(Fri)04:50:24
 安部氏に続き、福田氏が政権を投げ出しました。福田氏が政権をいずれ投げるであろうことはすでに見えており、どのタイミングで投げるか、投げるのは総選挙の前か後かが焦点とも言える状態になっていましたので、突然の辞任自体にこれといった驚きはありませんが、「安心実現内閣」を自称する内閣改造を行って1ヶ月で辞職するなどといった行為は大変疑問です。
 滑り出しはそれなりに順調であった福田氏ですが、なぜ最悪の形で辞職に追い込まれたのでしょうか。公明党の定額減税や再可決への難色などの押しに負けたという声もあれば、民主党の対決路線で追い込まれたという意見、大連立騒動が尾を引いたとする推測もありますし、さらには「小泉・安部内閣の負の遺産を引き継いでおり、最初から辞任は必至」などという、開始時点に原因を求める意見まであります。無論、このすべての原因が重なり合っての辞任なのでしょうが、果たして何が内閣にとっての致命傷となったのでしょうか。
 まずは福田氏の首相就任時点、すなわち「最初から辞任は不可避な状況にあった」という指摘ですが、確かに厄介な問題を多く引き継いではいたものの、これは直接的な辞任の原因ではないものと考えられます。なぜなら、低IQ選挙などの標的となる一部の人間を除けば、国民は政治家になめられるほどバカではないためです。福田氏が困難な課題を大量に抱えていることは分かっているのですから、国民はそれを踏まえて評価を行います。福田氏の低迷振りから分かるのは、困難を差し引いてもなお評価に値する行動をしていないと判断されたということです。
 大連立に関しては、確かに福田氏もダメージを受けてはいますが、民主党もダメージを被っていますので、これが政権の寿命を縮めたのは確かにしても、痛み分けの色彩が強いといえます。民主党の対決姿勢に関しても、民主党の存在によって法案がなかなか通らないのは最初から分かっていたことで、国民もそこは十分に承知していますので、民主党の対決姿勢の分を差し引いてもなお、福田内閣が評価されなかったことになります。政権末期の公明党の行動は、内閣にとってトドメの一撃となった可能性がありますが、公明党が無理にこのような行動を取り始めたのは、福田内閣がすでに窮地に陥っており、このままでは選挙に負けると踏んだためであって、これがなくても遅かれ早かれ終末を迎えていたでしょう。
 私の考えによれば、福田内閣の犯した最大の失敗は、全く道理のない再可決を用いてしまったことに他なりません。安部氏の後に福田氏が選出された理由は、福田氏の調整型・着実型の政治が必要であると考えられたためです。総裁選には自民党議員と党員しか関与できませんが、その後の全世論を対象とした支持率調査では、実際にそれなりの値を記録していましたので、福田氏の調整型の手腕はそれなりの期待を持って受け止められたといえます。
 ところが、民主党との調整を念頭において活動するとみられた福田氏は、間もないうちから再可決を乱用し始めます。私は福田氏の就任当初、この状況に最も対応できる者は氏であると考えており、ある程度はその手腕に期待していたのですが、再可決の時点で福田内閣を完全に見限り、内閣の終焉を予想しました。結果、全くその通りの結末となりました。
 この再可決により、福田氏に期待されていた調整型政治を氏が自ら放棄したことが判明した上、これは2世代前の郵政解散で得た議席を不当に再可決に使う行為であるため道理が通らず、さらには安部内閣の時に示された参院選での世論に対し、俗な言い方をするなら「中指を突き立てる」行為でもあるため、この時点で福田内閣の壊滅は半分決定したようなものです。福田氏は自らの長所に逆らい、さらにはその長所を買った世論の期待にも逆らったのですから、没落しない方がおかしいのです。
 結果、その後も道路特定財源問題などで再可決を使用することとなり、それによってさらに世論の支持が離れていく負のスパイラルに見舞われた上、福祉政策などの混乱がさらに没落に拍車をかけていきます。なお、福祉に関する諸問題は福田氏以前から存在したもので、世論は決して福田氏に全責任を押し付けることはしないはずですが、後期高齢者医療制度に関しては「低所得者ほど負担が軽い」というインチキ説明で不信感を増幅した上、制度自体が弱者ほどダメージが大きいものであったのに、先の「低所得者〜」といった嘘の説明や時限措置などでお茶を濁すことばかりを重視し、抜本的改革も打ち出さない始末です。年金に関しては、社会保障国民会議の詐欺的説明など、トリックがばれれば不信感を増大させるようなことを行いました。福祉問題は以前の政権から受け継いだ負の遺産でしたが、国民はその点を承知しているのですから、押し付けられた負の遺産そのものに対してではなく、それに対する福田氏の姿勢や手法が支持をさらに落とすに至りました。
 最終的に福田氏が残した成果はほとんどゼロに近いと言っても過言ではありません。道路特定財源の問題についても、あの状況下では福田氏でなくても絶対に手出しをしなければならなくなっていたはずであり、福田氏の手柄とはいえません。民主党の影響で法案が簡単には通らないにしても、この成果のなさは異常といえます。安心を実現したいのであれば、お得意の調整型の手腕を使用して、民主党と交渉してよりよい社会保障の制度を作ることもできたはずですし、少なくとも後期高齢者医療制度のインチキ説明や、「全額税否定ありき」の社会保障国民会議のトリック説明を使うことは、安心とは正反対の行為です。こうも最悪の状況となったのは、何といっても自らの長所を自ら破棄してみせ、世論の意思や期待に真っ向から背いたためでしょう。

 福田氏の辞任に伴い、今度は後継の問題が発生していますが、やはり人気は恐怖の麻生氏です。世論調査では「総理にふさわしい人」のダントツ1位となっており、小泉劇場の正当な後継者であることが伺えます。
 麻生氏は以前の総裁選でも「脳内メーカー知ってる人」といった発言を行うなど、「次の首相」として政策が問われるはずの総裁選で、政策とは全く関係ない語り口を用いて大人気を獲得しており、衆院選となれば低IQ選挙の再来が予想されます。低IQ選挙の愚かさや問題点は今までに再三指摘していますので、再び説明するまでもないでしょう。低IQ選挙となれば、とにかく目立った方が勝利してしまうため、政策論争その他は何の意味も持たなくなります。政策の議論は深まらず、深まったとしても選挙の結果、特に小選挙区の勝敗には何の影響も与えません。こうなると選挙など単なる人気投票に過ぎないため、資質に問題がありすぎる人間が乱立することも懸念されます。まじめに必死に政治の勉強をしている政治家志望の方々は、先の衆院選で当選した杉村氏や料理研究家を見てどのような感情を抱いたでしょうか。
 確かに、ここで麻生氏をトップにしてしまえば、自民党は選挙で相当に善戦できるでしょう。総裁選後、ご祝儀効果もあるうちに解散に打って出て、低IQ選挙で一気に議席を確保してしまえば、小泉内閣のように2/3を確保するまでは難しいとしても、単独過半数程度なら取れる可能性は十分あります。現在の自民党にとっては、麻生氏は救いの神とさえいえる状況でしょう。しかし、私はこれだけは断言できます。今の日本に求められているのは、「アキバ総理」ではありません。脳内メーカーを語るのではなく、政策を語るべきです。
 総裁選には恐怖の麻生氏の他、麻生氏と立場を異にして「上げ潮」路線を支持する候補も出ることになりそうです。勝負は麻生氏に分がありますが、総裁選は話題性のためにも有効なのでしょう。また、これも麻生氏が有利な点なのですが、民主党が仮に党首選をやると、政策の対立などから矛盾やちぐはぐな印象を世論に与えかねず、同党ではそれを懸念して党首選が回避されたのですが、麻生氏の場合は人気で票を集められるため、相対的に政策の細かい部分を考える人は少なくなり、また総裁選の主な争点は政策ではなく人気となり、マスコミも他の総裁候補による麻生氏の政策批判をあえて報道しようとはしないため、政策に矛盾があってもそうそう露見はしません。もし民主党が党首選をやっていたら、民主党党首選では小沢氏と他候補が互いに相手の政策の穴を指摘する小難しい論戦が報道される一方、自民党総裁選では麻生氏の「脳内メーカー」のような発言が延々と報道され続け、イメージに大きく差がつくことになります。本当は互いの政策の穴を指摘しあった方が選挙としては良いのですが、なぜか世論に対しては不利なのです。
 ところで、私は麻生氏を全く信用できないのですが、一方で「上げ潮」路線も全く支持していません。総裁選ではこれを掲げる候補が出てくることになりそうな上、麻生氏も完全に上げ潮路線を捨ててはいないように見受けられますので、簡単に解説しておきます。
 上げ潮路線は小泉内閣の手法とされており、規制緩和などで経済成長を発生・維持して税収を増やすなどすることを方針としています。確かに、ガチガチなまでの規制を緩和してやれば、活力が上がることは間違いありませんし、景気や税収にも影響が出るでしょう。派遣規制が緩和されて10年としないうちに、グッドウィルやフルキャストといった企業の存在が広く知れ渡り、一時期は両者ともドームの名前にまでなった(不祥事によって現在では変更)ことは、規制緩和の強力さを物語っています。
 麻生氏は財政出動による景気建て直しを方針としていますが、これは拠出がどうしても必要となるため、財政にダメージが出ることは避けられませんし、下手をするとバラマキになってしまいます。公明党の定額減税などはまさにこれの極端な例でしょう。増税によって収入を増やして財政を改善することは、景気を悪化させる恐れがありますし、何より嫌われるので選挙では持ち出しづらいテーマです。無駄の削減で出口の漏れを断つのも有効ですが、削減は無限にできるわけではありませんし、福祉などの必要なものを削減すると大変なことになります。
 その点、上げ潮は政策にもよりますが、規制緩和を行うだけで効果が期待できるのであれば、財政からの支出は最低限で済みます。さほど懐を痛めずに景気にテコ入れできる可能性があり、さらには増税しなくても税収が増える可能性もあります。その上、頭が上がらない経団連他の方々にも高く評価してもらえるのですから、これを好む自民党議員が多いのも当然のことです。
 しかし、「上げ潮」で何でも解決すると考えるのは誤りです。科学には「エネルギー保存の法則」なるものが存在しますが、これは経済にもある程度当てはまります。サブプライム問題から始まって、原油高や材料費・食料高騰などのマイナス要因のダメージを食い止めるには、エネルギーが必要です。それが財政出動であったり、景気対策であったりします。いずれにしても、それなりのコストがかかります。
 では規制緩和はどうでしょう。一見すると無から有を生み出す魔法のように見えます。しかし、そのような方策は未だに発見されていませんし、発見されているなら不景気など存在しないでしょう。
 規制緩和がエネルギーを生み出す構造は、何かが一定の状態に移行しようとするエネルギーと良く似ています。例えば水力発電では、水が下流に流れ落ちる力を利用して発電しています。状態の移行という意味では、ゴムやバネが元に戻ろうとする力も似たようなものでしょう。
 規制緩和における「一定の状態」とは、昨今の悪徳派遣などの状態を見ての通り、極端な格差が発生した状態を示します。日本などまたマシな方で、南アメリカの国家など貧困の著しい国では、都市全体がスラム化してゴーストタウンとなったり、強盗や殺人が当たり前になったりしています。つまり、規制緩和というものを簡単に表せば、日本をこのような状態に近づけるエネルギーによって、景気回復や税収増加を狙っているものであるといえます。無から有を生み出すのではない以上、そのツケが後で回ってくることは避けられません。
 無論、規制緩和がすべて悪いのではなく、新聞の特殊指定廃止のように絶対に必要な規制緩和も存在します。しかし、今の日本から派遣規制緩和のようなことを続けるのは自殺行為です。規制緩和によって景気回復や増収を見込む行為は、森林から大量の木材を取り出すようなものです。新聞特殊指定のような規制は、手入れせずに放棄されてしまった森林のようなものですので、規制緩和が必ずしも悪いわけではありませんが、昨今の規制緩和にはひどいとしか言いようのないものが多く存在します。それをさらに緩和しようというのは、壊滅寸前の森林からさらに材木を切り出すようなもので、これではあっという間にハゲ山化、あるいは砂漠化してしまうでしょう。
 麻生氏の低IQ選挙と「上げ潮」主張、どちらにも注意が必要となりそうです。

 現代においてもCOBOLが珍重されている理由は何でしょうか。負の遺産にすがっている人がいるからというのが模範解答なのですが、それではあまりにもCOBOLがかわいそうですから、ここは「ファイル処理に強いから」ということにしておきましょう。
 Cなどでは自分でファイルフォーマットを決定し、fopenなどの関数を使ってファイルを作成しなければなりませんが、COBOLではファイルの書き込みや読み込みのアルゴリズムを書く必要はありません。ファイル名と方式を指定すれば、その通りにファイルを作成してくれます。
 ファイルの編成方式には、RECORD SEQUENTIAL、LINE SEQUENTIAL、RELATIVE、INDEXEDの4種類があります(標準ではSEQUENTIALがRECORD SEQUENTIALとみなされるため、SEQUENTIALとだけ書いても構いません)。通常は何も指定しなければRECORD SEQUENTIALとみなされます。また、アクセス方法をSEQUENTIAL、RANDOM、DYNAMICから選ぶこともできます。その他、変数をキーに設定したり(副キーも設定でき、その場合は重複を許可するかも選択可能)、エラーステータスを受け取る変数を指定したりと、様々なことが可能です。
 まずは最も簡単なファイルの例から。ファイル名や編成方法などはENVIRONMENT DIVISIONに、ファイルの内容はDATA DIVISIONに書くのが決まりです。
IDENTIFICATION DIVISION.
	PROGRAM-ID. BLOG.

ENVIRONMENT DIVISION.
	INPUT-OUTPUT SECTION.
		FILE-CONTROL.
			SELECT FLANGS ASSIGN TO 'blog' FILE STATUS IS STAT.

DATA DIVISION.
	FILE SECTION.
		FD FLANGS.
			01 LANGS.
				03 NUM PIC 9(4).
				03 LANG PIC X(16).
	WORKING-STORAGE SECTION.
		01 STAT PIC XX VALUE '00'.

PROCEDURE DIVISION.
	MAIN-PARAGRAPH.
*		書き込み
		OPEN OUTPUT FLANGS

		MOVE 1 TO NUM
		MOVE 'COBOL' TO LANG
		WRITE LANGS

		MOVE 2 TO NUM
		MOVE 'C++' TO LANG
		WRITE LANGS

		MOVE 3 TO NUM
		MOVE 'C#' TO LANG
		WRITE LANGS

		MOVE 4 TO NUM
		MOVE 'Common Lisp' TO LANG
		WRITE LANGS

		CLOSE FLANGS

*		読み込み
*		まずファイルステータスを '00' にリセット
*		INITIALIZE は変数を VALUE で設定された値にリセットする命令
*		MOVE '00' TO STAT でも同じ
		INITIALIZE STAT

		OPEN INPUT FLANGS

		PERFORM UNTIL NOT STAT = '00'
			READ FLANGS
				AT END
*					読み込み終了
					CONTINUE
				NOT AT END
					DISPLAY LANGS
			END-READ
		END-PERFORM

		CLOSE FLANGS.
 ENVIRONMENT DIVISIONのSELECTがなかなかの厄介者で、最終的にはかなり長くなってしまうことが珍しくないのですが、COBOLの命令は基本的に英単語ですから、そこまで難しくはありません。何回かファイルを作っていれば、そのうち空で打てるようになります。ちなみに、最終的にどうなるかといいますと、
SELECT FLANGS ASSIGN TO 'blog'
	ORGANIZATION IS INDEXED
	ACCESS MODE IS DYNAMIC
	RECORD KEY IS NUM
	ALTERNATE RECORD IS LANG DUPLICATES
	FILE STATUS IS STAT.
 こうなります。この程度なら何度か打てば覚えられるでしょう。
 さすがにCOBOLだけあって冗長ですが、COBOLではISが省略できるものと定められており、上記のISはすべて省略できます。また、今回使用したFILE STATUSはSTATUSとだけ書くことも許されているため、「FILE STATUS IS ...」を「STATUS ...」と書いても構いません。ステータスに使う変数はWORKING-STORAGE SECTIONなど任意の位置に自分で作成しなければならず、型は英字2文字と定められています。つまり、XXまたはX(2)です。
 ファイルの中身はDATA DIVISIONのFILE SECTIONに書きます。ここのFDにも色々と設定項目があるのですが、ブロック長やブロック数といったテープデバイス用らしい項目が多く、設定しても効果はありません。今のところ書く必要はないでしょう。ファイルの内容の書き方は通常の変数の書き方と全く同じですので、迷う必要もないでしょう。
 後はPROCEDURE DIVISIONで処理するだけです。OPENにはINPUT、OUTPUT、I-Oの3種類があり、用途に応じて使い分けます。INPUTは読み込み、OUTPUTは書き込みが可能となっており、I-Oは既存のデータを修正できます。C言語などの書き込みモードと同様、OUTPUTは新規に空ファイルを作成するため、データの追加はI-Oで行う必要があります。今回はまずファイルに書き込みを行う必要がありますので、OUTPUTで開いてデータを書き込んでいます。処理が終わったら忘れずにCLOSEしなければなりません。
 後はそのデータを読み込むだけです。COBOLのCONTINUE文は単に何もしない(Pythonでいうpassと同様)命令なのですが、読み込めるデータがないのに読もうとするとファイルステータス変数が書き換わり、'00'以外のステータスが格納される(コンパイラ依存の可能性あり。私のOpenCOBOL環境では'10'に書き換え)ため、ループが終わります。結果、これでファイルが無事に読み込まれ、ループも終了します。
 以上、ここまでがCOBOLのファイル処理の基本なのですが、厄介なことにCOBOLには4種類の編成と3種類のアクセスモードが用意されています。また、レコードキーというSQL類似の概念まであり、こちらも編成次第で必須であったりします。さらに、アクセスモードによってはREADの使い方が変わってしまいます。ところが、この辺りは非常にややこしい割に、日本語のまともな資料が全く存在しない状態にあります。動作を知りたければ実際に作って確かめてみるしかありません。しかし、これがまた非常に厄介な仕様であるだけに、特性を調べるだけでもかなりの長さになってしまうため、ここは以後に回します。
 さて、次はCOBOL流の可変長配列について。文字列も数値も固定長なのがCOBOLの流儀ですが、珍しいことにCOBOLには一応可変長配列らしきものが存在しており、配列の個数を定めることができます。しかし、最大数と最小数を定め、その範囲内から好きな個数を指定するという一風変わった仕様になっており、不便さは否めません。C/C++やJavaの場合、メモリさえ許せば理論上はいくつでも配列を確保できますが、COBOLではそうはいきません。
 全く謎としか言いようのない仕様なのですが、この概念はファイルの編成方法と密接にかかわっています。それといいますのも、編成方法の中には全データを固定長で保存し、バイト数ずつスキップすることによってデータの頭出しを行うものがあるのです。例えばデータ長が20バイトなら、最初のデータから20バイトをスキップすることで次のデータの頭に移れます。逆に言えば、この編成方法ではすべてのデータのサイズが同じでなければならないため、あらゆるデータを最大長とみなさなければならないことを意味します。この編成方法では、可変長配列はその最大値のサイズが確保されるため、最大数を大きく設定しすぎるとファイルが肥大化します。なお、それ以外の編成方法であればこのようなことはありませんが、配列の未使用部分を切り詰めなければならない関係上、ファイルの末尾に置かなくてはならないようです。
 可変長配列のもう1つ重要な点として、ファイルには配列の長さを保存してくれないことがあります。WORKING-STORAGE SECTION内で使う場合はともかく、ファイルで用いる場合は注意が必要です。ファイルから可変長配列を含むデータを読み込んだとしても、配列の個数は決して分かりません。これを回避したいのであれば、手動で配列長を保存する必要があります。
 可変長配列は以下のように作成します。
OCCURS 0 TO 10 DEPENDING ON VARNAME
 このOCCURSは通常のOCCURSと同様、好きな変数につけることができますが、01レベルの変数につけることはできません。ファイルの場合はこれを末尾のデータにする必要があるようです。0 TO 10の部分には最小値と最大値をそれぞれ指定し、VARNAMEには何らかの変数を指定します。この変数の値が配列のサイズになります。可変とはいえ基本的には配列ですので、通常の配列と同様に、INDEXED BYを使ってインデックス変数を作成させることもできます。
 以下は可変長配列を用いたプログラムの例です。
IDENTIFICATION DIVISION.
	PROGRAM-ID. BLOG.

ENVIRONMENT DIVISION.
	INPUT-OUTPUT SECTION.
		FILE-CONTROL.
			SELECT FLANGTYPE ASSIGN TO 'blog'
			FILE STATUS IS STAT.

DATA DIVISION.
	FILE SECTION.
		FD FLANGTYPE.
			01 LANGTYPE.
				03 NUM PIC 9(4).
				03 TYPENAME PIC X(16).
*				配列長を保持する変数
*				WORKING-STORAGE SECTION に書いてもよいが
*				その場合は配列長が保存されなくなる
				03 ARRLEN PIC 9(2).
				03 LANGS.
*					0〜10個の間で可変の長さの配列を作成
					05 LANG PIC X(16) OCCURS 0 TO 10
						DEPENDING ON ARRLEN 
						INDEXED BY IDX.
	WORKING-STORAGE SECTION.
		01 STAT PIC XX VALUE '00'.

PROCEDURE DIVISION.
	MAIN-PARAGRAPH.
*		書き込み
		OPEN OUTPUT FLANGTYPE

		MOVE 1 TO NUM
		MOVE 'Cの後継' TO TYPENAME

*		配列長変数に書き込むことで配列長を変更できる
		MOVE 4 TO ARRLEN
		MOVE 'C' TO LANG(1)
		MOVE 'C++' TO LANG(2)
		MOVE 'Java' TO LANG(3)
		MOVE 'C#' TO LANG(4)

		WRITE LANGTYPE

		MOVE 2 TO NUM
		MOVE 'SQL' TO TYPENAME

		MOVE 1 TO ARRLEN
		MOVE 'SQL' TO LANG(1)

		WRITE LANGTYPE

		MOVE 3 TO NUM
		MOVE 'マークアップ' TO TYPENAME

		MOVE 2 TO ARRLEN
		MOVE 'HTML' TO LANG(1)
		MOVE 'XML' TO LANG(2)

		WRITE LANGTYPE

		CLOSE FLANGTYPE

*		読み込み
*		まずファイルステータスを '00' にリセット
		INITIALIZE STAT

		OPEN INPUT FLANGTYPE

		PERFORM UNTIL NOT STAT = '00'
			READ FLANGTYPE
				AT END
*					読み込み終了
					CONTINUE
				NOT AT END
					DISPLAY NUM ':' TYPENAME
					PERFORM VARYING IDX 
						FROM 1 BY 1 UNTIL IDX > ARRLEN
						DISPLAY '	' LANG(IDX)
					END-PERFORM
			END-READ
		END-PERFORM

		CLOSE FLANGTYPE.
 使う機会がどれほどあるのかは不明ですが、これで可変長配列らしきものを使うことができます。ちなみに、可変長配列の長さ以上の部分にもデータを書き込むことができ、しかも正常に読み出せることから考えて、どうやら処理上はメモリに最大数までの領域を確保しているものと推測されますので(処理系によって異なる可能性あり)、CやJavaなどと違ってメモリの節約には役に立ちそうもありません。
カテゴリ [開発魔法][社会問題][経済・知的財産] [トラックバック 0][コメント 0]

開かずの門
2008/07/12(Sat)00:02:14
 諫早湾の干拓問題について、漁業関係者らが水門を開放するよう求めた裁判で、佐賀地裁は「水門を開放して5年間調査を行う」との判決を下しました。水門と漁業の損失に因果関係が存在する可能性を認めた判決でしたが、国側が控訴を決定したため、水門の開放は当面なくなりました。
 洞爺湖サミット前には北極をあしらったポスターを作り、サミットでも環境問題を主張、排出量取引の導入を検討するなど、福田氏はどうも環境問題重視を気取りたいようですが、この一事が完全に矛盾を露呈しています。水門と漁業の因果関係を実証実験なくして証明するのは極めて難しく、現状で漁業への影響が存在するのか、存在したとしてどの程度かは現時点では分かりませんが、少なくとも水門やダムなどといった工作物はもともとの環境を破壊するものであるため、環境にやさしいわけがありません。水門やダムの中にはどうしても必要なものもありますが、治水その他の事業の明確なメリットが示せないのであれば、単に環境を破壊するものでしかありません。実際、この水門は費用対効果の面などから批判を受けています。
 ましてや、判決では「今すぐ水門を取り壊せ」ではなく、「5年間様子を見るべき」とされています。実際にやってみなければ漁業への影響がはっきりしない以上、まず調査してみるのは妥当です。その上で何もないというのであれば、水門は少なくとも漁業にかかわる海洋環境を破壊していないことが明白になり、漁業の面から水門事業に文句をつけられる筋合いはなくなります。逆に何らかの影響を与えていることが分かれば、水門は海洋環境を破壊していることになります。
 開放実験なくして漁業への影響は確かめようがなく、しかも早い段階で開放した方がダメージが少ないにもかかわらず、何としても開放を阻止しようとする政府の姿勢には、海洋環境の破壊がバレては困るためではないかと勘繰りたくもなります。政府にそこまでの意図があるかはともかくとしても、環境破壊の可能性について調査してみようという意思は全くないようです。
 このように、福田氏が本当に環境問題を考えているかは大変あやしいのですが、もし環境問題に真摯に向き合う気がなく、単に人気取りのフレーズにしようとしているなら、そのようなことはやめるべきです。このまま環境破壊が進めば全世界の総生産が20%も減少するというショッキングな調査結果もあり、未来の利益の保護のためにも環境を重視するのは大事なことですが、ろくにやる気もないくせに環境を強調したところで、反感を買うだけです。無法派遣や後期高齢者医療制度、原油・食料高などで悲鳴を上げている最中に、流氷と白クマのポスターなどを見せられたところで、国民が共感するわけがありません。ガソリンの暫定税率問題の際、町村氏が「(25.1円の)税率を下げるどころか、環境のために上げることもある」などと発言していたように記憶していますが、水門1つ取っても環境への配慮が見られない内閣がそれをしかねないのです。冗談ではない、というのが多くの国民の本音ではないでしょうか。
 このまま裁判が長引けば、結論が出るのがいつになるのか想像もつきません。また、もし水門が海洋環境に影響するのであれば、時間が経つほど不可逆的な変化が生じる恐れも強くなります。仮に10年もして水門を開けるよう結論されたとしても、そのころにはもはや海洋環境が破壊されており、状況はほとんど回復しない、ということもあり得るのです。さらに、その時には干拓地の利用も今より増えているはずですので、こちらへのダメージも甚大になります。
 そもそも、この事業には効果に見合わない多額の費用が必要との指摘があり、漁業被害の可能性も予想されるなど、無駄遣いの可能性が高いものでした。ダムやその他の工作物の例を見ても明らかですが、国の組織は1度始めた事業を取りやめることを嫌います。こうした批判がありながら、結局水門を作ってしまった上、その水門を何としてでも開けようとしないのは、いわゆる「メンツ」のためでしょうか。
 裁判がこのまま高裁や最高裁までもつれ込んだとして、これらの裁判所の判断も気がかりです。特に最高裁は、原告にかなりの分があるケースであっても、大抵は国の勝訴となってしまうよう見受けられます。このまま控訴審や上告によって時間をつぶされ、最終的には最高裁で原告敗訴ということになれば、おそらく水門が海洋環境に与えた影響はうやむやにされたまま終わることになるでしょう。
 以前、いくつかの訴訟で国の敗訴が相次いだ際、政府が検討したのは「裁判能力の強化」でした。敗訴が相次いでいるから敗訴をしないようにということなのでしょうが、完全にピントがずれています。窮地に立たされている原告に比べ、国は資金も時間も人間も情報もほぼ無限に持っており、圧倒的に優位な立場にあります。その上に裁判能力強化となれば、国の理不尽な行いに対抗することはより困難になります。「理不尽な行いを訴えられても、裁判で叩き潰せば無問題」などという理屈がまかり通っては困ります。裁判能力を強化する余裕があるのなら、そもそも裁判を起こされないようにすることに力を注ぐべきです。水門問題にしても、最高裁なら国が勝訴する可能性は十分にありますが、これは何の解決にもなりません。単に「水門が海洋環境にどのような影響を与えたか」という疑問が闇に葬られるだけです。
 ともかく、国は早いうちに開門調査に応じるべきでしょう。調査の結果、漁業や海洋への影響がないことがはっきりすれば、調査はそれで済みます。また、海洋の環境を破壊しているのであれば、早期に開門しなければ不可逆的な環境破壊を招く恐れがあります。長引けば干拓地の利用も進むため、いざ調査となると大変なことになります。いずれにせよ早期開門が最もダメージの少ない方法です。

 ある新聞社のコラムで、「株式の持ち合いは株主に利点を説明できない」といった内容のものがありましたので、それについて少々。
 確かに、株式の持ち合いにはデメリットが多く、日本の悪しき習慣としてかねてから批判を浴びています。取締役がその地位を追われることはなく、第三者に買収される緊張感もなくなりますし、株主に配慮する必要もなくなります。結果、本来なら取り替えられるような経営陣が居座り、企業価値もへったくれもない経営を行い、株主総会では全案確定というわけです。なるほど、ろくなことがないように見えます。
 しかし、必ずしも是認できるものではありませんが、持ち合いが必要悪、あるいは最近の市場動向への適応であると考えられるケースも存在します。その場合でも持ち合いの負の側面を引き受けることになるため、どのような場合に適当なのかは非常に微妙な問題なのですが、一元論で判断できるほど簡単ではありません。
 コラム内では「持ち合いに使う資金は設備投資にまわすべき」ということも書かれているのですが、事はそう単純ではありません。突然の敵対的買収に対応するため、買収防止策など様々な対策を行わざるを得ず、そのせいでかなりの費用を使用したという本末転倒な事例もあります。このようなことになっては、設備投資どころではありません。
 また、PBRが高い企業は敵対的買収を仕掛けられやすいとされ、設備投資をサボればそうなるのだと言わんばかりの論調も見たことがありますが、ゲーム業界など当たり外れが大きい業界はどうしても資産の確保が必要らしく、これはどうしようもありません。
 一方で、このところ自己利益しか考えないファンドが幅を利かせている事実があります。ファンドのすべてがそうであるとは言いませんし、ファンド以外にもそのような組織はありそうですが、いずれにせよ傍若無人な行動は株主と消費者の害になりかねません。有名なグリーンメーラー・村上ファンドの例では、ある企業は執拗に身売りを要求され、また同ファンドのターゲットにされた企業は業績が低迷する傾向にあったという調査結果も出ていました。こうなってしまえば、まともな長期的株主にとっては迷惑千万というものです。
 ブルドックソースの例では、多くの株主が敵対的買収に反対し、結果として防衛策が発動されるに至りましたが、この防衛策ではファンドに「毒薬」分の株式の代わりとなる多額の現金が渡っています。これによる損失は利益を大きく上回るほどのもので、当然のことながら利益を得たのはファンドだけ、ファンド以外の人々は大迷惑です。
 他にも、とある企業が何らかの技術や特許、その他のれんとなるアドバンテージを持っていたとして、それを得た上で会社の不要な資産は全部処分、従業員をポイ捨てするような買収も考えられます。外国では「〜パラシュート」規定によって役員や従業員の解雇を極めて困難にすることが行われているようですが、日本ではそれが合法かさえ分かっていません。
 これらを低コストで解消する手段が「持ち合い」であるとしたら、一概には責められないのではないでしょうか。買収防衛策にはコストが必要となり、防衛しなければファンドに資産を根こそぎ奪われる可能性があり、何かもっと良い防衛策を考えようにも法的な裏づけがないという有様ですから、持ち合いが絶対に株主利益と相反するとはいえません。
 マスコミであれば、買収されそうになっても「表現の自由が損なわれる」と大声で騒ぎ立て、次いで国民をマインドコントロールして買収に反対させ、大抵は相手を追い払うことができますが、マスコミ以外はそうはいかないのです。

 Schemeといえば継続、継続といえばScheme。この概念はSchemeにしかない上、どうも非常に理解しがたいらしく、困っている人も少なからずいるようです。なお、概念自体は以前にこちらの記事でも取り扱っています。
 さて、まずは継続とは何でしょう。この記事にいくらか詳しく書いていますが、要はラベルつきbreakのようなものです(あまり知られていませんが、実はJavaの言語仕様に含まれていたりします)。ただし、ラベルつきbreakと違って値を返せますので、ラベルつきreturnとでも表現するのが分かりやすいでしょう。
 ところで、継続を学習・理解する上で、まずやらなければならないことがあります。先の記事では、Wikipediaや他のサイトの解説として以下のような例を挙げています。

「プログラミングにおいてある計算過程のある瞬間における、その過程の未来全体(デフォルト)を表すもの」
「計算過程の実行スナップショットと説明される」
「継続は、実行中のどんな計算機プログラムにも存在する」
「しかし継続の概念は、ほとんどのプログラミング言語では明示的に扱われていない」
「(+ (+ 5 10) 15)の処理は、5に10を足した結果を取得し、それに15を足して返す処理。5に10を加算し、その後15を加算するという処理自体が継続であり、ほぼすべての言語に存在する」

 継続を習得する上で、一番最初にやらなければならないのは、これらの記憶を封印することです。実際、こうした文章を読んでもイマイチ意味が理解できず、継続自体が良く分からないということはよくあるようです。全部忘れてください。覚えていても役に立ったためしがありません。
 それでは、継続とは一体何なのでしょうか。

1.継続はラベルつきreturnである
 実際にそのようなものはありませんが、概念として考えれば分かります。以下、「正の数なら0を返し、負の数なら正の数にして返す」仮想Javaコードです。当然のことながら、実際には動作しません。
private int getUnsigned(int data){
	if(data < 0)
		absolute(data);
	return 0;
}

private int absolute(int data){
	return getUnsigned -data;
}

private void user(){
	getUnsigned(10);
	getUnsigned(-5);
}
 この仮想コードでは、absoluteのreturn文でgetUnsignedまで値を返すようにラベルを指定しています。
 もう1つ例を。これは1つ目の引数を2つ目の引数で割り、その値を文字列として返す関数です。ただし、0で割られたら"NaN"を返すものとします。
private String divString(int l , int r){
	int result = div(l , r);
	return String.valueOf(result);
}

private int div(int l , int r){
	if(r != 0)
		return l / r;
	return divString "NaN";
}
 ラベルつきreturn文は、ラベルで指定したメソッドに成り代わって値を返すため、Stringで値を返します。
 上記コードは仮想コードですから、本物のJavaで実行することはできません。そもそもメソッド名をラベルにしていては、再帰呼び出し後のreturnの際にどこまで戻れば良いのか分かりません。しかし、実際に使用こそできませんが、これが継続の概念です。

2.継続は例外に似た処理である
 今度はまともに書けるプログラムを考えてみましょう。先ほどと同様に、割り算を行うメソッドであるdivと、その結果を文字列にして返すdivStringがあるとします。
private String divString(int l , int r){
	return String.valueOf(div(l , r));
}

private int div(int l , int r){
	return l / r;
}
 しかし、これではゼロ除算を判定できません。ゼロ除算の場合はそれが分かるようにしたいものです。divStringメソッドに手を加えれば簡単ですが、divメソッドにしか手を加えてはいけないとして、一体どうすれば呼び出し元に異常を伝えられるでしょうか。
 これを解決するスマートな方法は、やはり例外です。
private int div(int l , int r){
	if(r == 0)
		throw new RuntimeException("NaN");
	return l / r;
}
 これでゼロ除算になることが分かった時点で例外を投げ、そうでなければ普通に結果を返してくれます。
 しかし、継続は例外とは少々違い、途中で投げた例外も、通常の処理による正常なreturnも、どちらも同じように返り値として受け取ります。

 概念はここまでとして、実際に使ってみましょう。継続はcall-with-current-continuation関数で使用できます。しかし、あまりに長い関数名であるため、call/ccと略すことが慣例となっているようです。
(define call/cc call-with-current-continuation)
 通常、call/ccには1つの引数を持つラムダを渡します。ラムダではなく関数を渡しても問題はありませんが、ラムダの方が便利なことが多いため、大抵はラムダを使います。
 まずは最も単純なケースから。call/ccは使用していますが、継続の概念は使用していません。
(print
	(call/cc
		(lambda (x) "Continuation")
	)
)

-> "Continuation"
 ラムダの返り値がそのままcall/cc関数の返り値になっていることが分かります。このように、call/ccに渡した関数が返した値は、そのままcall/cc関数の返り値になります。
 今度は継続の概念を使ってみましょう。
(print
	(call/cc
		(lambda (x)
			(x "Continuation")
		)
	)
)

-> "Continuation"
 やたら難しく説明される「継続」ですが、実際はこれだけです。ラムダの1つ目の引数は、まさに「ラベルつきreturn」と同じ機能を持っています。すなわち、これに渡した値がそのままcall/cc関数の返り値になるのです。なお、継続がreturn文や例外にたとえられることからも分かるように、これを呼び出した時点でcall/ccを抜けるため、ラムダ内のそれ以降の処理は実行されません。
(call/cc
	(lambda (x)
		(print "ここは実行される")
		(x "Continuation")	; ここで抜ける
		(print "ここは実行されない")
	)
)
 例外と同様、いかに深いネストからでも一発で抜けられます
(print
	(call/cc
		(lambda (x)
			(let ((str "Continuation"))
				(if #t
					(let loop ()
						; これを呼んだ時点で
						; call/cc まで抜ける
						(x str)
						; 以下は実行されない
						(loop)
					)
				)
			)
		)
	)
)

-> "Continuation"
 当然ですが、通常の返り値と継続による返り値を混在させても構いません。先ほどの割り算を継続で考えてみましょう。ゼロ除算でないなら割った結果をそのまま返し、ゼロ除算なら"NaN"を返すものとします。
(define (div left right)
	(call/cc
		(lambda (x)
			(if (= right 0) (x "NaN"))
			(/ left right)
		)
	)
)

(div 10 5)
-> 2

(div 10 0)
-> "NaN"
 この程度であれば継続によらなくても簡単に実装できますが、それを言っては継続の習得ができません。まず、(= right 0)が真であれば(x "NaN")を実行します。これは継続ですので、呼ばれた時点でcall/ccは"NaN"を返します。(= right 0)が偽であれば(/ left right)の結果を普通に返します。ラムダの返り値はcall/ccの返り値となりますので、call/ccは割り算の結果を返します。
 もう少し高度な例を。schemeにはloopなどといった制御構文はありませんが、名前つきletで簡単に実装できます。
(let loop ()
	...
	(loop)
)
 しかし、これは無限ループです。このままでは使い物になりません。if文を使って無限ループにならないようにすることはできますが、可能ならCommon Lispのように(return ...)で値を返しつつ、同時にループも抜けたいものです。
 そこで継続の出番です。
(define (factory max)
	(let ((i 1) (result 1))
		(call/cc
			(lambda (return)
				(let loop ()
					(if (> i max) (return result))
					(set! result (* result i))
					(set! i (+ i 1))
					(loop)
				)
			)
		)
	)
)
 継続にreturnという名前をつけているため、(return value)でcall/ccの外側に値を返すことができます。その結果、Common Lispと似たような使い方が可能になっています。
 ちなみに、関数の中身はごく普通の階乗です。
(factory 5)
-> 120

(factory 10)
-> 3628800
 さらに、継続の中に継続を入れることもできます。継続はいくつでもネストできる上、最も内側の継続関数から最も外側の継続まで一気に抜けるなど、自由な処理が可能です。
(call/cc
 (lambda (outer)
  (call/cc
   (lambda (inner)
    (call/cc
     (lambda (deep)
      (print "ここは実行される")
      (outer)	; 一気に外側まで抜ける
      (print "ここは実行されない")
     )
    )
    (print "ここも実行されない")
   )
  )
  (print "ここも実行されない")
 )
)
 また、breakやcontinueのマネをしたり、例外や脱出gotoと同等の処理を行うこともできます。
; 0 から 15 までループし、2の倍数をリストに格納する処理
(let ((datas null))
 (call/cc
  (lambda (break)
   (let loop ((i 0))
    (call/cc
     (lambda (continue)
      ; i が15以上であれば break
      (if (> i 15) (break))
      ; i が2の倍数でないなら continue
      (if (not (= (modulo i 2) 0)) (continue))
      ; リストにデータを追加
      (set! datas (cons i datas))
     )
    )
    (loop (+ i 1))
   )
  )
 )
 (print (reverse datas))
)

-> (0 2 4 6 8 10 12 14)
 以上、過剰なまでに難しいと言われる「継続」が、実際には大変簡単であるとお分かりいただけたことでしょう。
カテゴリ [開発魔法][社会問題][経済・知的財産] [トラックバック 0][コメント 0]

<-前のページ [1] [2] [3] [4] [5] [6] [7] [8] 次のページ->
- Blog by yamicha.com -