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 件の中から 21-25 件を表示しています。
私的利権権益補償金
2008/05/10(Sat)00:13:38
 著作権利権団体の主張をほぼ丸のみして作られた「テレビ番組のダビング10(コピー9回制限)を導入したければ、iPodなどへの私的録画録音補償金を認めよ」という脅迫案が、メーカーの反対によって見送りとなりました。この案ではiPodなど携帯音楽プレイヤーには課金するものの、PC用HDDなどの汎用性が高い機器には課金しないものとされていますが、メーカー側は「対象が際限なく拡大する恐れがある」として反対しています。
 現状では、デジタル放送には「コピーワンス」と呼ばれる制限がかかっており、DVDなどのメディアには1回しかコピーすることができません。また、DVDにコピーすると元のデータは削除されるため、もしDVDへのコピーが失敗してしまえば、コピーしようとした映像は永久に失われます。本来ならコピー制限を解除して対応すべきところなのですが、ここで出された奇策が「ダビング10」でした。これは9回までコピーが可能で、10回目はコピー後に元のデータが削除されます。
 一方、携帯音楽プレイヤーへの課金はかねてから著作権利権団体が強く主張していたもので、現状ではCDやDVDレコーダー、CD及びDVDのメディア自体の他、携帯音楽プレイヤーに似たものとしては携帯MDレコーダーなどに課金されています。これらの機器やメディアの購入代金には補償金が含まれており、著作権利権団体に渡るようになっています。当然のことながら、CDやDVDをデータ保持や自分の創作物のために利用しても課金されます。
 最近のなりふり構わない著作権利権団体の横暴には驚かされますが、コピー制限を課すこと自体は現状と何ら変わらない、「ダビング10」などという卑劣なおためごかしによって、音楽プレイヤー課金への譲歩を引き出そうとは、卑怯としか言いようがありません。このようなやり口は、製品の質によって売り上げが落ちたのを違法コピーのせいにして、CDにコピーガードをかけて販売した音楽メーカーのそれと全く同じです。
 メーカーが携帯音楽プレイヤー課金に反対したのは、とりあえず妥当な措置といえるでしょう。そもそも私的録画録音補償金自体が不透明かつ不当なものですし、これを音楽プレイヤーに課金されるいわれはありません。さらに、今回の脅迫的な交換条件に用いられているデジタル放送コピー制限の緩和は、本来音楽プレイヤーとは何の関係もありません。また、著作権利権団体のなりふり構わぬ行動からして、これを認めれば今後PC用HDDなどあらゆる装置に対して課金を要求してくる可能性が極めて高く、ここで断固として拒絶する必要があります。
 そもそもメーカーはダビング10自体を受け入れるべきではありません。コンテンツにコピー制限を課すこと自体が問題であり、コピー回数が10回でも256回でも制限されている限りは意味がありません。また、デジタル放送を放送局らによる独占利権企業B-CASが牛耳っていることが問題の根底にあり、これらを打破しない限り利用者不在の状況は続きます。
 著作権利権団体側は「製作者の権利を守るために必要」などと聞こえの良いことばかり主張していますが、百歩譲って現行の補償金制度が妥協点としてやむを得ないものであるとしても、コピーワンスやダビング10では私的録画が大幅に制限されるのですから、少なくともこれらを行うレコーダーについては補償金を課すことはできないか、または著しく減額しなければならないはずです。その上、基本的に音楽や映像を保存することしかできないVHSやDVD、MDレコーダーと、HDDにデータを保存することができる携帯音楽プレイヤーでは、質的に大きな違いがあることは否めませんので、仮に現状を肯定したとしても課金を容認する理由にはなりません。ましてや、PCのHDDにまで課金するなど論外です。
 文化庁も文化庁で、著作権利権団体の代弁者となるのではなく、多少はコンテンツ利用者の方を向くべきでしょう。おそらく裏で金銭授受なり天下りなりが行われていることが想像できますが、それにしても昨今の利権団体の横暴にはすさまじいものがあります。今回の例を見るまでもなく、文化庁は私的録画録音補償金の導入や拡大を推進している他、著作権の期限が切れる映画について屁理屈同然の主張を行い、より著作権期限を長くみなすようなこじつけを行っていました。無論、このような文化庁の主張が認められるわけもなく、裁判にて期限切れが認定されました。
 著作権利権団体にしても、横暴な論理でくだらない主張を繰り返すより、まずは作品の質を考えるべきでしょう。無限回のコピーやインターネットへのアップロードが可能であるとしても、良い製品であれば何の問題もなく売れますし、いくらコピーガードなどの利用者締め付けを強めたところで、悪いものは売れません。これはCCCD騒動を見ての通りです。作品の質を棚上げし、利用者を締め付けた上に補償金を少しでも多くふんだくろうなどとは、コンテンツ作成者の風上にも置けません
 音楽プレイヤーばかりかPCのHDDなどにも課金することになって人々の怒りを買い、デジタル放送のコピー制限は存続して利用者に不便を強い、それでいて一部の技術者によって放送の暗号化が破られ、一般利用者が制限に苦しむ中で裏の利用者のみがコピーを解除してインターネット配信なり非合法DVDなりを作る、という結末が見えるようです。

 京都・舞鶴の事件で、遺族がマスコミに手記を発表しました。毎度のことながら報道自粛を申し入れる文言が盛り込まれており、またしても報道被害が発生していることが分かります。さらに、これも毎度のことではありますが、マスコミによってはこの手記の全文を引用することはなく、事件について語った部分のみを引用した上で、報道被害については「自粛を申し入れた」とだけ書いて済ませています。
 特にひどいのが読売新聞のWebサイトでの引用で、犯人について「絶対に許すことはできません」とした部分まで手記を引用していながら、その後に続く「マスコミの皆様〜」の部分を全部切り落として隠蔽しています。報道の権力を盾にした言論封殺行為も同然です。
 いつも不思議で仕方がありませんが、報道協定を結ぶなり節度ある取材を申し合わせるなりしてもこのような取材を行う有様なのでしょうか。それとも、遺族に言われなければ節度ある取材をしないのでしょうか。どちらにしてもあきれ果てる所業というしかなく、「被害者は2度死ぬ」ことをまざまざと示しています。
 これまでにも再三取り上げているように、このような悪質な取材は今に始まったことではなく、以前に女児殺害が連続して発生した際にもほぼ例外なく遺族がマスコミの横暴を訴え、遺族の自宅に無断で不法侵入したり、家の前に空き缶やタバコの吸殻を投げ捨てていることが明らかになりました。また、被害者の関係者宅に押しかけて写真を譲り受けたり購入したりすることも常態化しているようです。以前に精神科医の調書漏えいや報道のねつ造などが発覚した際、マスコミは報道の自殺などとして大げさに騒ぎ立てましたが、このような野蛮な取材行為を行うことこそ報道の自殺です。
 こうした残虐極まりない取材に対し、見るに見かねて誰か(主に政治家など有力者)が苦言を呈しでもしようものなら、必ず「報道の自由の侵害だ」「国民の知る権利だ」などという意味不明な主張によってマスコミの大反発を浴びることになりますが、報道の責任を守らぬ以上は報道の自由はありませんし、被害者の家にタバコや空き缶を撒き散らした上での取材結果や葬式に押しかけた挙句の取材結果を見たいと望む国民はそうそういないでしょう。
 報道被害を防止する組織としてBROなどがありますが、所詮はアリバイ工作の延長線上の組織に過ぎず、十分な効果が期待できないのが現状です。被害者に対する報道被害は一向になくなりませんし、被疑者は相変わらず犯人扱いされるばかりか、科学的根拠のない血液型占いの1つたりともやめさせることができません。
 現代社会では誰でも事件の被害者になる可能性がありますし、冤罪で犯人にされてしまう可能性もあります。どちらにしてもマスコミにとことんなまでにプライバシーを暴かれ、名誉をズタズタに毀損される結末となります。いつ自分がその立場に立たされるか分からない以上、他人事では済まされません。
 報道被害が発生するたび、マスコミは自主規制の効果と権力介入の不当性を唱えてきましたが、自主規制は一向に進展を見せません。時間は十分すぎるほどありましたが、どうやらマスコミに改善する意思はないようです。自主規制によって報道被害を抑制することが絶対に不可能であると分かった以上、場合によっては免許剥奪もある非常に厳しい罰則を設け、報道被害による2度目の殺人やセカンドレイプから被害者を守るしかありません。法による介入を控えて自主規制に任せている限り、報道被害が改善することは未来永劫、120%起こりません。
 法によって報道被害から被害者を守るとなれば、権力による恣意的な運用ができないようにする必要はありますが、報道の責任を果たさぬ報道の自由があり得ない以上、「報道の自由の侵害」の声を恐れてはいけません。今のところこのような法案が出される予定は見られませんが、可能な限り早い段階での制定を希望します。

 続・Haskell。今回はHaskellでマトリックスです。とはいえ、これはやや以前に組んだものであり、Sequenceの使い方があまり分からない状態で作っているため、少々無駄が多いのではありますが。
 まずはHaskellのクラスモデルのおさらいから。Haskellにはclassとdataがあり、classは主にプロトタイプ宣言を記述するもので、dataは構造体に類似しています。Javaに例えるとclassはインタフェースに似ていますが、Haskellのクラス内では関数の宣言を行うことができます。ただし、クラス自体は抽象的なものであって実体となるデータを持たないため、クラス内で定義されたオペレーションを組み合わせて実現できる処理のみを実装することしかできません。
class PlusClass a where
	zero :: a
	plus :: a -> a -> a
	multi :: a -> Integer -> a
	-- multi の処理が「zero に対して指定された回数だけ値を足し合わせる」
	-- ものであれば、クラス内の関数宣言のみを使って構築可能であるため
	-- クラス内で実装を定義できる
	-- この実装が不適切なら instance でオーバーライドできる
	multi a m = recmulti a m zero where
		recmulti a m result
			| m > 0 = recmulti a (m - 1) (result `plus` a)
			| otherwise = result

data IntegerData = IntegerData{
	var :: Integer
}

instance PlusClass IntegerData where
	zero = IntegerData 0
	plus a b = IntegerData $ (var a) + (var b)

main = var $ (IntegerData 16) `multi` 16
-- class 内での実装のおかげで、結果は 256
 性質こそインタフェースに似ていますが、HaskellのクラスはHaskellのクラス以外の何者でもありません。
 次にdata、これはほとんど構造体です。構造体と違うのは、instance宣言によって特定のクラスと結びつけ、実装を提供できる点です。これは「Haskellのクラスたるインタフェースをインプリメントしたクラス」と似ていますが、やはりHaskellのインスタンスであるとしか言いようがないものです。つまり、Haskellはdataごとに固有の実装を持ちます。無理にOOPに例えるより、発想を転換して考えた方が理解は容易です。
 ちなみに、クラスには複数の型を取るものがありますが、これはStateなどで平気で使われているにもかかわらず、Haskell 98標準には含まれていない上、仕様としても要検討とされているものです。
 クラスには、型を用いるものと「型のタグ付け」を行うものの2種類があります。通常のクラスは大抵が前者で、後者はモナドが有名です。「タグ付け」を行うと、タグにされた型が独自にデータを持つことができます。以下にごく単純な例を示します。
-- このクラスは通常のデータ型と違い、「タグ」に用いる
class CountTag m where
	inc :: m a -> m a
	dec :: m a -> m a
	getcount :: m a -> Integer
	make :: a -> m a

-- そのインスタンスは対象のデータを保持するようにする
data CountData a = CountData{
	count :: Integer ,
	member :: a
}

-- インスタンスを生成
instance CountTag CountData where
	inc a = a{count = (count a) + 1}
	dec a = a{count = (count a) - 1}
	getcount a = count a
	make a = CountData 0 a

-- CountData が String とは別にデータを持っている点に注目
-- 当然のことながら、String のデータも問題なく保持されている
some :: CountData String
some = inc $ make "SomeData"
main = getcount some
 おさらいはここまでにして、マトリックスの実装です。
import Data.List
import Data.Foldable
import Maybe
import Data.Sequence

-- Matrix
data Matrix = Matrix{
 matrixData :: [[Double]]
}

class (Show a) => MatrixOperation a where
 cols :: a -> Int
 rows :: a -> Int
 get :: a -> Int -> Int -> Double
 set :: a -> Int -> Int -> Double -> a
 multiply :: a -> a -> a
 getList :: a -> [[Double]]
 getListT :: a -> [[Double]]
 inverse :: a -> Maybe a

instance MatrixOperation Matrix where
 cols m = Prelude.length $ (matrixData m) !! 0
 rows m = Prelude.length $ matrixData m
 get m r c = ((matrixData m) !! r) !! c
 set m r c s = m{matrixData = newRows} where
  getCols = (matrixData m) !! r
  newRows = toList $ update r newCols (fromList (matrixData m))
  newCols = toList $ update c s (fromList getCols)
 multiply m n = Matrix (multirc (getList m) (getListT n) []) where
  multirc (mr:mrs) nrs result = multirc mrs nrs 
   (result ++ [multic mr nrs []])
  multirc [] nrs result = result
  multic mr (nr:nrs) result = multic mr nrs (result ++ [prod mr nr 0])
  multic mr [] result = result
  prod (m:mr) (n:nr) result = prod mr nr (result + m * n)
  prod [] [] result = result
 getList m = matrixData m
 getListT m = transpose (matrixData m)
 inverse m = (swappingList (initialList 
  (matrixData m) (rows m)) (rows m)) >>= 
  (inverseList (rows m)) >>= 
  (return . Matrix . (map (Prelude.drop (rows m))) . toList) where
  initialList l size = initialrc l 0 [] size
  initialrc (mr:mrs) i result size = initialrc mrs (i + 1) 
   (result ++ [mr ++ (naturalRow i size)]) size
  initialrc [] i result size = result
  naturalRow i size = (replicate i 0) ++ [1] ++ 
   (replicate (size - i - 1) 0)
  swappingList list size = swapping (return (fromList list)) size
  swapping seq size = seq >>= (checkSwap 0 size)
  checkSwap i size seq
   | i >= size = return seq
   | (seq `index` i) !! i == 0 = (return seq) >>= 
    (searchSwap i size) >>= (checkSwap (i + 1) size)
   | otherwise = (return seq) >>= (checkSwap (i + 1) size)
  searchSwap i size seq = search i 0 size seq
  search :: Int -> Int -> Int -> 
   Seq [Double] -> Maybe (Seq [Double])
  search rowi i size seq
   | i >= size = Nothing
   | (((seq `index` rowi) !! i) /= 0) && 
    (rowi < i || (((seq `index` i) !! rowi) /= 0)) = 
    return $ flip rowi i seq
   | otherwise = search rowi (i + 1) size seq where
    flip i1 i2 seq = update i2 (seq `index` i1) 
     (update i1 (seq `index` i2) seq)
  inverseList :: Int -> Seq [Double] -> Maybe (Seq [Double])
  inverseList size seq = inversing 0 size seq
  inversing i size seq
   | i >= size = return seq
   | otherwise = (return seq) >>= (setDivLine i) >>= 
    (iterMinusLine i 0 size) >>= (inversing (i + 1) size)
  setDivLine :: Int -> Seq [Double] -> Maybe (Seq [Double])
  setDivLine i seq = setDivLineExec i seq ((seq `index` i) !! i) where
   setDivLineExec i seq d
    | d == 0 = Nothing
    | otherwise = return $ adjust (\list -> (Prelude.take i list) ++ 
     (map (\x -> x / d) (Prelude.drop i list))) i seq
  iterMinusLine :: Int -> Int -> Int -> Seq [Double] -> 
   Maybe (Seq [Double])
  iterMinusLine row i size seq
   | i >= size = return seq
   | i == row = iterMinusLine row (i + 1) size seq
   | otherwise = iterMinusLine row (i + 1) size (setMinusLine row i seq)
  setMinusLine row i seq = update i (minusLine row i seq) seq
  minusLine row i seq = (Prelude.take row (seq `index` i)) ++ 
   (minusExec (Prelude.drop row (seq `index` row)) 
   (Prelude.drop row (seq `index` i)) ((seq `index` i) !! row) [])
  minusExec (r:rs) (x:xs) prod result = minusExec rs xs prod 
   (result ++ [x - (r * prod)])
  minusExec [] [] prod result = result

instance Show Matrix where
 show m = show $ matrixData m
 これで完成です。関数名はほとんど見ての通りで、getListTはtransposeしたリストを返すものです。transposeはリストのX,Yを入れ替えるもので、Haskellリファレンスでは次のように説明されています。これはmultiply演算に便利です。
transpose [[1,2,3],[4,5,6]] == [[1,4],[2,5],[3,6]]
 後はMatrixコンストラクタにDoubleの2次元配列を渡せば、乗算でも何でも好きな動作を行うことができます。inverse関数で逆行列を求めることもできますが、逆行列は失敗する場合があるため、Maybeモナドを使用しています。乗算してその逆行列を求め、それをさらに乗算するような場合、Maybeを次々と組み合わせることで、成功すれば演算の結果を得られ、失敗ならNothingを返すことができます。
 しかし、手作業でマトリックスを構築するのはかなり骨ですので、ヘルパークラスを用意してみました。
class (MatrixOperation a) => MatrixCreator a where
 -- 指定したサイズのマトリックスを生成
 createMatrix :: Int -> Int -> a

 -- 乗算しても何もしないマトリックスを生成
 -- createNatural は X,Y,Z、createNaturalH は X,Y,Z,H
 -- (以下に記述した instance 宣言の実装の場合。以下同様)
 -- createNaturalCustom は指定した次元のそれを生成する
 createNatural :: a
 createNaturalH :: a
 createNaturalCustom :: Int -> a

 -- 「位置」を表すマトリックスを生成する
 -- これに対して回転やスケーリングを次々と乗算していくことで
 -- 操作実行後の位置を求められる
 createPosition :: Double -> Double -> Double -> a
 createPositionH :: Double -> Double -> Double -> a

 -- 回転を行うマトリックスを生成する
 -- 1つ目の引数が回転軸、2つ目が度数(rad)
 createRotate :: Int -> Double -> a
 createRotateH :: Int -> Double -> a

 -- 移動を行うマトリックスを生成する
 -- 移動軸である H が必須である
 createMoveH :: Double -> Double -> Double -> a

 -- スケーリングを行うマトリックスを生成する
 createScale :: Double -> Double -> Double -> a
 createScaleH :: Double -> Double -> Double -> a

instance MatrixCreator Matrix where
 createMatrix x y = Matrix $ replicate y (replicate x 0)
 createNatural = createNaturalCustom 3
 createNaturalH = createNaturalCustom 4
 createNaturalCustom a = natural (createMatrix a a) 0 a where
  natural result i m
   | i < m = natural (set result i i 1) (i + 1) m
   | otherwise = result
 createPosition x y z = Matrix [[x , y , z]]
 createPositionH x y z = Matrix [[x , y , z , 1]]
 createRotate a t = setRotate petern createNatural a t where
  setRotate ((a1 , a2 , oper):xs) m a t = setRotate xs 
   (set m (axis (a1 + a)) (axis (a2 + a)) (oper t)) a t
  setRotate [] m a t = m
  petern = [(1 , 1 , cos) , (1 , 2 , sin) , 
   (2 , 1 , (sin . (*)(-1))) , (2 , 2 , cos)]
  axis x = x `mod` 3
 createRotateH a t = setRotate petern createNaturalH a t where
  setRotate ((a1 , a2 , oper):xs) m a t = setRotate xs 
   (set m (axis (a1 + a)) (axis (a2 + a)) (oper t)) a t
  setRotate [] m a t = m
  petern = [(1 , 1 , cos) , (1 , 2 , sin) , 
   (2 , 1 , (sin . (*)(-1))) , (2 , 2 , cos)]
  axis x = x `mod` 3
 createMoveH x y z = setMove createNaturalH [x , y , z] 0 where
  setMove m (x:xs) i = setMove (set m 3 i x) xs (i + 1)
  setMove m [] i = m
 createScale x y z = setScale (createMatrix 3 3) [x , y , z] 0 where
  setScale m (x:xs) i = setScale (set m i i x) xs (i + 1)
  setScale m [] i = m
 createScaleH x y z = setScale (createMatrix 4 4) [x , y , z] 0 where
  setScale m (x:xs) i = setScale (set m i i x) xs (i + 1)
  setScale m [] i = m
 それでは実際に使ってみましょう。まずは単純に、1,0,0をZ軸で45度回転させ、それからX2,Y2,Z5だけ移動させてみます。
main = show $ (createPositionH 1 0 0::Matrix) `multiply` 
	(createRotateH 2 (pi / 4)) `multiply` (createMoveH 2 2 5)
-- "[[2.70710678118655,2.70710678118655,5.0,1.0]]"
 最後の1.0はH軸ですから関係ないとして、1,0,0をZ軸45度回転で0.7071...,0.7071...,0、それを2,2,5動かせば上記の通りの結果となります。
 逆行列も試してみましょう。以下の式では「Z軸45度」を「Z軸45度の逆行列」で打ち消しているため、マトリックス乗算の単位元が返されることになります。
main = (createRotateH 2 (pi / 4)::Matrix) `multiply` 
	(fromJust (inverse (createRotateH 2 (pi / 4)::Matrix)))
-- [[1.0,0.0,0.0,0.0],[0.0,1.0,0.0,0.0],[0.0,0.0,1.0,0.0],[0.0,0.0,0.0,1.0]]
 無論、いつでもどこでもinverseが成功するとは限りません。例えば下記の例の場合、dには次の値が格納されます。
1	0	0	0
0	0	0	0
0	0	1	0
0	0	0	1
 これはinverseできませんので、Nothingとなります。Maybeを使用しているのはそのためで、この場合の結果はNothingとなります。
main = do
	let a = createPositionH 1.0 0 0::Matrix
	let b = createRotateH 2 (pi / 8)::Matrix
	let c = a `multiply` b
	d <- inverse $ set createNaturalH 1 1 0
	let e = c `multiply` d
	let f = e `multiply` createRotateH 1 (pi / 4)::Matrix
	return f
 このような具合に、Maybeをひたすら重ねていくようにすれば、inverseのたびに失敗処理を書く必要はありません。
カテゴリ [開発魔法][社会問題][経済・知的財産] [トラックバック 0][コメント 0]

野村の内部情報取引商品
2008/04/27(Sun)21:47:01
 野村証券の社員がインサイダー取引を行っていたことが発覚しました。野村といえば最大手の有名な証券会社ですが、そこが「率先して」インサイダー取引を行っていたのですから、衝撃はかなり大きいようです。
 しかも、それを行ったのが合併や買収をアドバイスする部門の人間であったというのですから、不適切などというものではありません。アドバイスを受けるに当たっては、相手企業もアドバイザーに十分な情報を公表するはずですし、非開示情報も含めてその企業の動向を逐一知っていなければアドバイスなどできませんから、一般には公表されない良質かつ大量の情報が集まるであろうことは容易に想像できます。
 この情報を不正に用いて取引を行うのは重大な背信行為であり、情報の目的外利用もはなはだしいものです。私は野村と相手社のアドバイス契約についての資料を持っておらず、また相手社との関係上詳細が公表されることもないでしょうが、このような機密情報のやり取りを行うような契約を結ぶ際には「情報の目的外利用をしない」ことを定めるのが普通です。そして、もしそのような契約締結が行われているのであれば、信義上の問題も避けられません。
 しかも今回の問題は明らかに確信犯で、「インサイダーの意図はない」などという言い訳も不可能なほどです。そもそも証券会社の人間がインサイダーに関して学ぶのは当然ですから、仮にインサイダー取引について知らずに取引を行い、後でそのような言い訳をしたとしても何の免罪符にもなりませんが、今回の例では被疑者らが明らかにインサイダーであることを認識していたとみられ、野村と無関係の人が共犯として代わりに取引を行うことで、事件の発覚を回避しようとしています。
 おそらく公取委などの取り締まり側は、インサイダーの疑念のある取引を厳しく監視・調査しているのでしょうが、まさかすべての取引を監視することはできません。つまり、このようなケースが他に存在する可能性は否定できません。以前にNHKや日経の社員が不正な取引を行っていましたが、似たような手法で不正な取引を行いながら、「替え玉」を使うことで発覚を回避している例がないと言い切ることはできません。
 さらに、いくら証券会社やマスコミが内規を作り、株取引を厳しく制限したり、内部情報でのインサイダー取引を規制したとしても、外部の協力者に取引をさせるのでは手の出しようがありません。誤ってインサイダー取引をしないようにするために、社員に対して説明や教育などを受けさせたとしても、確信犯には何の効果もありません。
 このように、インサイダー取引を100%防止することはほぼ不可能です。内部情報を知る者が存在する以上、そこにインサイダー取引が発生する疑念は常にあり、最終的には個々の倫理に頼るか、すでに発生したものを事後に取り締まる以外に防止する方法はありません。
 この問題の現実的な解決策の1つは、徹底した情報の分離を行うことです。報道関係社であれば報道上必要な社員にのみ報道内容を伝達し、証券会社のアドバイザーなら各案件の詳細が無関係の者に伝わらないように「密閉」することで、関係のない者が情報を聞きつけてインサイダー取引を行うことを防止できます。実際、株式投資を行っている会社では、内部情報を知る恐れがある業務部門と株式投資部門を明確に分離し、インサイダーの疑念が生じないようにしているところも多いようです。
 インサイダー規定をめぐる極端な例では、村上ファンドの一連のグリーンメール事件において、村上氏がターゲットの会社に対して「今から株式を購入する」と連絡を入れ、インサイダー規定によって相手社が十分な防衛策を取れないようにした上で、攻撃を仕掛けたこともあったといいます。自分はろくにインサイダー規定を守らないくせに、規定が他者にとって都合が悪い場合は十分に活用する辺り、実に村上ファンドらしいともいえる事例ですが、インサイダー規定の厳密さや難しさがよく表れています。
 村上ファンドから始まって、NHK、日経、そして野村証券と、最近は内部情報を不正利用したインサイダー事件が相次いでいます。日本では今のところインサイダー取引について周知されているとは言いがたく、軽い気持ちで違法な取引に手を出してしまう例もあれば、野村のケースのように迂回工作までした確信犯の例もあるでしょう。インサイダー取引は極めて不公正な取引行為なのですから、マスコミや証券会社など内部情報に触れる機会が多い業界を中心に、教育や情報分離などによるインサイダー取引の防止が重要であることは言うまでもありません。

 吉野家が仕入れた米国牛から危険部位が発見されました。米国側は工場のミスとした上で日本側が輸入停止措置を取ることを否定し、日本側も輸入停止措置を行わない方針です。吉野家は「厳格な検査体制によって未然に危険部位を発見した」ことを強調し、牛肉の安全性を主張しています。政府は抜き取り調査の比率を10%に増やすことを表明し、小売店の中には米国牛を回収したところもあるようです。
 日本が再び輸入停止措置を取るべきかは、ここではあえて述べません。そもそも輸入再開の判断からして疑念が極めて多いため、またしてもこのような事例が発生することは最初から予想されたものであり、ある意味で発生して当然とさえいえます。しかし、米側の行動の不当さや不可解さについては指摘しておかなくてはなりません。
 日本の安全措置について、米国はたびたび「過剰反応」であると指摘しています。以前に輸入停止措置が取られた際も、米国はこれを過剰反応であると批判しており、今後再び輸入停止ということになれば、やはり米国は同様の主張を行うことでしょう。また、国内からも日本の対応が過剰であるという批判が出ることがあり、実際に過剰であるか適正であるかはともかくとして、過剰であるという主張にはある程度の説得力があります。
 しかし、度重なる米国の背信行為はそのような論では説明できません。これまでの日本の反応からして、米国側は日本に危険な製品を輸出すれば「過剰反応」が発生すると認識していたはずなのです。ところが、「過剰反応」が発生するであろうことが明らかであるにもかかわらず、輸入再開から何年と経たないうちにわざわざ「過剰反応」が発生するようなミスを犯すのですから、日本を極めて甘く見ているか、または安全対策が非常におざなりかのいずれかとしか考えられないのです。科学的な安全性の問題などを差し置いても、この1件だけで輸入停止措置を取ることができるほど重大な問題です。
 いくら米国や輸入存続派が「科学的に安全」などという理屈をひねり出したところで、米国が背信行為によって危険な牛肉を送ってきた事実は変えられません。「科学的に安全」なら相手との契約に背き、信頼を破壊しても構わないなどという道理はどこにもありません。輸入停止までは不要というならそれでも構いませんが、日本が違反に「過剰反応」して輸入停止論が出ることは最初から分かりきっているというのに、米国側があえて契約違反を行ったにもかかわらず、なお輸入停止を行わない理由を政府は説明しなければなりません。
 抜き取り検査にしても、必ずしも安全性を向上するものではありません。今回の問題では700箱中の1箱に危険部位が見つかりましたが、ランダムに1つの「ハズレ」を混ぜた集団からその10%を抽出し、それでハズレが見つかる可能性といえば、たったの10%に過ぎません。政府はまた「農水省と厚労省の2重の検査体制」を主張していますが、両方の抽出件数がそれぞれ10%であるなら発見可能性はせいぜい20%、同じサンプルを重複調査する可能性があるなら19%です。20%そこらでは厳格な検査とは到底いえません。後は輸入業者がそれを見逃せば、危険部位は見事に国内で流通することになります。なお、輸入業者の全箱検査義務は2007年6月で終了しています。
 無論、「危険部位が1つ2つ流出した程度では、CJDが日本で発生する可能性は極めて低い」との主張もあるでしょうが、最も恐ろしいのはこのような主張によって危険部位流通が正当化されて「常態化」し、本当に危険性が上がってしまうことです。また、それによる危険発生確率がいかに低かったとしても、「危険部位は送らない」という契約に違反した責任はいささかも減りません。
 また、日本が広く用いている屠殺・処理方法では、危険部位の血液などが食用部位に混ざる危険があるなどと主張する声もあります。それを理由に米国牛の安全性を相対的に訴える主張もありますが、日本のやり方に危険があるならそれを改めるべきは当然としても、それは米国牛の問題とは何の関係もありません。日本の処理方法が安全であろうと危険であろうと、米国牛の危険部位の感染リスクが下がるわけではなく、しかも危険部位を送ってきたことに対する責任が緩和されることは全くありません。
 輸入停止論には触れないとしても、この状態でこれ以上の輸入規制緩和を行うのは到底不可能であることだけは間違いないでしょう。米国側は規制緩和を主張していますが、契約違反をすれば日本側が「過剰反応」し、それによって緩和反対圧力が高まることを米国は国としても輸出工場としても承知していたはずですから、これも自分でまいた種です。

 名物問題・全国学力テストの数学B。今回もざっと目を通してみましたが、残念ながら面白い問題はほとんどありませんでした。「お得なセットメニュー!」のような問題があればSQL編のネタにしてやろうと考えていただけに残念です。
 しかし、このまま何もないのでは面白くありません。せっかくですから番外編を。

 SQL・リスト内包編。湖めぐりのリスト内包は走る。

魔道士イリアス「えーと、同じ種類の釘をたくさん用意しました。釘全体の重さを量ったところ、400グラムでした。・・・釘全体の重さが分かっているとき、釘の本数を求めるためには、釘一本の長さ、重さ、太さのうち何を調べればいいか?・・・何よこの問題」
騎士サーラ「ああ、学力テストの問題ですか」
魔道士イリアス「いくら私でも間違いようがないわよ。重さの問題なのにどうして長さとか太さとかを調べるのよ」
騎士サーラ「そこはご愛嬌ですよ」
魔道士イリアス「図形問題は意味分からないから飛ばして・・・富士山の問題ね。富士山五湖めぐりコースには山中湖、河口湖、西湖、精進湖、本栖湖があるらしいわね」
騎士サーラ「はい」
魔道士イリアス「5つの湖のうち2つの湖で写真を撮影するとき、2つの湖の選び方は全部で何通りあるかを求めなさい。ただし、湖に行く順番は考えないものとします・・・だって」
騎士サーラ「妙に軽い問題ですね・・・」
魔道士イリアス「これはシークェルしかないわね。さあ、解いてみるわよ」
騎士サーラ「イリアスさん、この程度のものにCREATE TABLEを打つおつもりですか?」
魔道士イリアス「だって、SQL編はそういう問題だし・・・」
騎士サーラ「ここはHaskellのリスト内包で求めてみましょう」
魔道士イリアス「リスト内包?それってすごいの?」
騎士サーラ「すごいも何も、クイックソートが数行で書けるのですから。今回の問題は短縮すれば1行、分かりやすく書いても2行か3行で足ります」
魔道士イリアス「確かにすごいわね・・・」

 リスト内包表記で見事に問題を解くことができるでしょうか。

模範解答
 湖が5つあり、回るのはそのうち2つです。さらに順番は考慮しません。となれば、答えはもはや明らかです。
result = length [(show a) ++ "," ++ (show b) | 
	a <- lake , b <- lake , a < b] where
	lake = [1 , 2 , 3 , 4 , 5]
 この結果は10ですから、すなわち10通りあることが分かります。

魔道士イリアス「これだけ?あっけないわねえ・・・」
騎士サーラ「問題作成者は、これがリスト内包で解かれるなどとは絶対に考えてはいないでしょうが・・・。リスト内包なら湖名を含んだ結果も出せますからね」
魔道士イリアス「湖名も?どうやって?」
騎士サーラ「方法はほとんど同じです」
result = [(snd a) ++ "\t" ++ (snd b) | 
	a <- lake , b <- lake , (fst a) < (fst b)] where
	lake = [(1 , "山中湖") , (2 , "河口湖") , (3 , "西湖") , 
		(4 , "精進湖") , (5 , "本栖湖")]

main = mapM_ putStrLn result
騎士サーラ「結果はこの通りです」
山中湖	河口湖
山中湖	西湖
山中湖	精進湖
山中湖	本栖湖
河口湖	西湖
河口湖	精進湖
河口湖	本栖湖
西湖	精進湖
西湖	本栖湖
精進湖	本栖湖
魔道士イリアス「これだけのコードで?何か本当に魔法を見ているような気分ね」
騎士サーラ「何をおっしゃいますか、イリアスさん。あなたも開発魔道士ではありませんか」
魔道士イリアス「でもウィザードには程遠いのよねえ・・・」

 SQLを使うまでもない問題ですから、全く面白くありません。これ以外にSQLが有効に使えそうな問題もなく、今回の学力テストは拍子抜けでした。ちなみにmapM_は(a -> m b)と[a]を取ってm ()を返す関数で、モナドの副作用(上記の例ではSTDOUTへの出力)が重要な場合に用いるものです。
 リスト内包はここまでとして、HaskellのStateモナドです。Stateは2つのデータを使って2つのデータを返すもので、Parsecなどでも使われています。ReaderとWriterを組み合わせたような性質を持っていますが、いくつかの差異があります。

・環境の値とモナドの値の2つを受け取る。環境の値はReaderと同じく後から指定できる。
・Writerと同じく、モナド内に値を2つ持つ。
・Writerとは違い、値の片方をMonoidに限定されない。StringでもIntegerでも好きなものを使用できる。
・Readerと同じく、モナドは「環境の値を引数に取る関数」を取る。ただし、この「環境」の値はReaderのそれとは異なり、Stateが持つ2つ目の値(Writerではログに当たるもの)である。
・その関数内ではWriterと同じくタプルを返す。タプルの2つ目が環境の値としてバインド後のStateに引き渡される。

 つまり、WriterのログがReaderの環境として回されるのがStateなのです。Writerのようにログを自動的に書き込んではくれませんが、値をかなり自由に制御することができます。当然のことながら、ReaderやWriterと同じ動作をさせることもできます。
 まずはWriterと同じ動作をさせる例を考えてみます。Writerでは自動的に追加されるログの部分がStateでは追加されず、その代わりログの値が環境として回されるのですから、
someState :: State [String] Integer
someState = State (\e -> (10 , e ++ ["put 10"])) >>=
	(\v -> State (\e -> (v + 50 , e ++ ["plus 50"]))) >>=
	(\v -> State (\e -> (v * 2 , e ++ ["multi 2"]))) >>=
	(\v -> State (\e -> (v - 75 , e ++ ["minus 75"])))

main = runState someState []
 こうなります。
 次にReaderの場合を考えてみましょう。Readerは環境の値を使用時に渡して使いまわす一方、StateではWriterのログのようにして逐次変更できますが、すなわち環境の値を変更しないStateはReaderと同じ動作ができるのですから、
someState :: State Integer Integer
someState = State (\e -> (e , e)) >>=
	(\v -> State (\e -> (v + e * 2 , e))) >>=
	(\v -> State (\e -> (v + e * 3 , e)))

main = runState someState 10
 これで無事に動作します。ただ、Stateは値と環境のタプルを返しますので、値だけが欲しければ
main = evalState someState 10
 このように書きましょう。
 また、例によってStateにもいくつかの関数が用意されています。Stateは他のState系モナドに比べて自由度が高いため、関数もそれを踏まえたものが色々と存在します。
 まずは理解が極めて容易なevalStateとexecStateから。evalStateは先の通り、値のみを取る時に使用するものです。execStateはWriterでいうログのみを取る時に使用します。これらはサンプルを出す必要すらないでしょう。
 次にwithState。これはシグネチャを見れば一目瞭然です。
withState :: (s -> s) -> State s a -> State s a
 すなわち、環境の値に手を加えてStateに渡す動作を行うStateを生成します。
someState :: State Integer Integer
someState = State (\e -> (e , e)) >>=
	(\v -> State (\e -> (v + e * 2 , e))) >>=
	(\v -> State (\e -> (v + e * 3 , e)))

main = runState (withState (\x -> 10) someState) 1
 このようにすれば、runState時の環境の値として何が渡されたかにかかわらず、10が環境の値として最初のStateで用いられます。また、
withState (\x -> x * x) someState
 であれば環境の値が2乗されて渡されます。Readerのlocalに似た機能といえそうです。
 次にmapStateを。これのシグネチャは以下の通りです。
mapState :: ((a, s) -> (b, s)) -> State s a -> State s b
 値がタプルである点、及びaがbになっている点が気になります。
 それでは実際に使ってみましょう。
someState :: State Integer Integer
someState = State (\e -> (e , e)) >>=
	(\v -> State (\e -> (v + e * 2 , e))) >>=
	(\v -> State (\e -> (v + e * 3 , e)))

main = runState (mapState (\(a , b) -> (show a , b)) someState) 10
 これの結果は「"60",10」です。もともとの型はState Integer Integerですが、mapStateによってState Integer Stringに変換されています。また、これは見ての通りタプルですから、当然のことながら環境の値も渡されており、その両方を変更することもできます(環境の値は型を変更できません)。
 それからWriterのlistenに似たget、書き込みを行うput、三人称のgetsも用意されています。
get :: m s
put :: s -> m ()
gets :: MonadState s m => (s -> a) -> m a
 まずgetから。これはlistenですから、環境の値をデータ値にコピーしてしまいます。
someState :: State Integer Integer
someState = get

main = runState someState 10
 これで(10 , 10)が得られます。
someState :: State Integer Integer
someState = State (\e -> ("dummy" , e * 2)) >>
	get

main = runState someState 10
 こうすると(20 , 20)です。getによってデータ値の"dummy"は破棄され、代わりにその時点の環境の値が格納されます。
 こうして使用している限りはあまり使い道がなさそうですが、do記法と組み合わせると便利です。do記法の<-で取得できるのは、>>=で用いる関数の引数に渡される値であるため、データ値に環境の値をコピーして返してくれるgetを使用すれば、<-を使って簡単に環境の値を取得できるようになります。さらに、そうして書き換えた環境の値はputで書き込めます。
someState :: State [String] Integer
someState = do
	v1 <- return 10
	put ["put 10"]

	v2 <- return $ v1 + 100
	m2 <- get
	put (m2 ++ ["plus 100"])

	v3 <- return $ v2 * 2
	m3 <- get
	put (m3 ++ ["multi 2"])
	return v3

main = runState someState []
 条件分岐などを活用すれば、かなり色々なことができそうです。
 getsはgetとほぼ同じですが、データを取得する前に任意の値に書き換えることができます。
someState :: State Integer String
someState = do
	msg <- gets show
	return $ "environment:" ++ msg

main = runState someState 100
 最初にgets showを用いることで、msgには環境の値が文字列化されたものが格納されます。後はそれに"environment"の文字列を連結して返していますので、main実行時には「("environment:100",100)」が得られます。
 最後にmodify、これもシグネチャからおおむね想像できます。
modify :: MonadState s m => (s -> s) -> m ()
 先ほどのget,put,getsのシグネチャと見比べてみましょう。
get :: m s
put :: s -> m ()
gets :: MonadState s m => (s -> a) -> m a
 getに対するgetsとputに対するmodifyは似ているようです。これを使用すると、getとputを組み合わせる作業をまとめて行うことができます。先ほどのget及びputのサンプルをmodifyで書き換えてみましょう。
someState :: State [String] Integer
someState = do
	v1 <- return 10
	put ["put 10"]

	v2 <- return $ v1 + 100
	modify (\msg -> msg ++ ["plus 100"])

	v3 <- return $ v2 * 2
	modify (\msg -> msg ++ ["multi 2"])
	return v3

main = runState someState []
 あるいはカリー化を利用して
someState :: State [String] Integer
someState = do
	v1 <- return 10
	put ["put 10"]

	v2 <- return $ v1 + 100
	modify (++ ["plus 100"])

	v3 <- return $ v2 * 2
	modify (++ ["multi 2"])
	return v3

main = runState someState []
 なかなかスマートに書けることが分かります。
 Stateはモナドの中でも有名で、Parsecなど実用もされているライブラリですから、この辺りを押さえておくと面白いものが書けそうです。
カテゴリ [開発魔法][社会問題][経済・知的財産] [トラックバック 0][コメント 0]

子どもと電力
2008/04/17(Thu)23:13:55
 英国の「ザ・チルドレンズ・インベストメント・マスターファンド」は、現在9.9%を保有している「Jパワー」株を20%取得するよう申請しましたが、経済産業省及び財務省はこれを認めない決定を下し、中止勧告を出しました。ファンド側が従わなければ中止命令を出す方針です。
 公開株式は外国人投資家やファンドも含めて自由に売買できるのが原則ではありますが、電力会社など公共性の高い企業が利益本位の外資に牛耳られた場合、社会混乱や国民への不利益が生じる可能性がありますので、外為法はこれらの株式を10%以上取得する外資に申請を義務付けており、もしそれによって問題が生じる恐れがあれば、中止勧告や命令を出すことができます。
 ところで、この規制には外為法のどの条文が適用されるのでしょうか。それらしい部分を探してみたところ、外国為替及び外国貿易法(外為法)の26〜27条付近がそれに当てはまりそうです。同法によれば、「対内直接投資等」とは「政令で定める率以上」の株式を購入するなどの行為のことであり、対内直接投資等について「政令で定めるものを行おうとするときは」「政令で定めるところにより」届け出を行わなければならないものとされています。
 それでは、この「政令」では一体何が定められているのでしょうか。こちらも探してみたところ、どうやら対内直接投資等に関する政令がそれに当たりそうです。2条5項で「百分の十」であることが定められており、6項で「電気事業」が示されています。電気事業の他にも、銀行や保険業、ガス事業、金融商品取引業などが含まれるようです。また、3条2項1号のイでは投資に審査が必要な業種について次のように規定されています。

国の安全を損ない、公の秩序の維持を妨げ、又は公衆の安全の保護に支障を来すことになるおそれがある対内直接投資等に係る業種

 法や政令にも明記されている通り、この規定は「公の秩序の維持」を目的として存在していることが分かります。
 それでは今回の中止勧告は妥当といえるのでしょうか。ファンド側を擁護する意見も散見されますが、私は勧告や命令もやむを得ないと考えています。株式の取引は基本的に自由であるべきとはいえ、国民や国家の基盤である電力事業会社が外資ファンドの「オモチャ」となるようなことがあれば、社会的な混乱と不利益は避けられないためです。
 無論、今回の英ファンドがそのような意図を持っていると言い切ることはできません。しかし、同じく外資ファンドのスティールの例を見てみても、強引な買収や投機的な売り抜けをもくろんだり、露骨で過度な利益還元を求めるなどしており、ブルドックソースが買収防衛策を株主総会にかけた際には8割もの賛成が得られるなど、他の株主からの評判も芳しくありません。国内の村上ファンドですら、入手した株を高値で売り抜けることを目的に、投資先の会社に身売りするよう圧力をかけていたといいます。これらの行為が一般の業種に対して行われるだけでも時に混乱を生じるのですから、これが社会基盤業種となると問題はさらに大きくなります
 その点を考慮すれば、ある程度の規制がなされることは仕方がありません。ファンド側は「規制によって長期的投資が遠ざけられ、日本経済に悪影響が出る」と主張していますが、野放図な投機で国家に悪影響が出ることこそ懸念すべきなのですから、投資活動を多少制限したとしても規制には合理性があります。
 ここからは余談ではありますが、外資と公共的な会社の株といえば、フジサンケイグループ及びTBS株の問題は記憶に新しいところです。放送事業も公共的な色彩が強い業務であり、万が一外国資本が放送事業を掌握してしまうと大変なことになりかねないため、外国の投資家が所持できる議決権の量に制限が課されており、外資による会社の支配は実質的に困難な仕組みになっています。
 しかし、ここで問題になったのがライブドアの行動です。ライブドアがフジに手を出すのは企業規模からしてもかなり無謀であり、株式転換付き社債を外資のリーマン・ブラザーズに引き受けてもらうことで、ニッポン放送の買収資金などを調達していました。この場合、実質的に外資の資金が放送会社に流れ込んでおり、その後の展開によっては外資が実権を持つ可能性がありますが、当時の法律ではこれが規制されていませんでした。これではまずいということで、少し後に法改正が行われています。
 また、楽天がTBSに手を出した際には「委任状争奪戦」が生じる可能性もありましたが、議決権の制限から権利を持たない外国人投資家も存在したようで、問題がかなり複雑になっていました。公開株式は基本的に売買が自由とされており、公共的な事業だからと規制をかける方が例外であるため、公の利益のためにやむを得ないとはいえ、状況によっては様々な問題や矛盾が生じてきます。
 現状のテレビなり新聞なりが公共の利益を重視しているかといえば、どう考えてもYESと答えることは到底できませんが、下手に外国資本が入って外国のプロパガンダチャンネルができても困りますので、制限はやむを得ないと考えるべきでしょうか。
 外為法による中止勧告は今回のJパワーに対するものが初めてのようですが、今後とも買収なり外国ファンドの投資なりといった行動は増えることはあっても減ることはないでしょう。今後は申請を認めるかどうか微妙なケースなども出てくることが予想されますが、その際に政府がどのような方針を採り、どのような判断を下すのかが見ものです。

 児童ポルノ問題に関して、自民党の小委は写真などの単純所持をも違法とする一方、アニメなど被害者が存在しないものは違法としない方針を固めました。民主党も公明党もアニメ規制には慎重な姿勢であるため、今後単純所持が処罰される法案が提出されたとしても、創作物は当面規制対象から外れそうです。
 被害者のいない創作物について論じる以前に、そもそも単純所持に罰則を求めること自体が異例のケースであるため、被害者が存在するであろう実写物をめぐっても、単純所持まで規制すべきかは意見が分かれるところです。これを生産、売買、または取り引きする人間が罰せられるのはともかくとして、所持するのは自由であるとする考えも少なからず存在するでしょう。
 ちなみに私は単純所持への罰則もやむを得ないと考えています。他の法律との整合性を考えても、例えば児童買春行為は「需要」側も罰せられますし、拳銃や麻薬は所持しているだけで罰せられます。拳銃や麻薬などの所持が違法なのは公共の危険を避けるためである一方、児童ポルノについては被害者の二次被害を回避する側面が大きいとはいえ、需要側が合法であるため供給が続いて被害者が増えることを考えれば、一応矛盾はありません。
 しかし、このような規制が必要であることは明らかではあるものの、私はどうしても所持違法化に賛成する気にはなれません。捜査機関が適正かつまともに法律を運用するなら導入しても問題はありませんが、Winnyの作者を著作権法違反で逮捕し、さらにはウイルス作成者までもを著作権法違反で逮捕してしまうという、どう考えてもその法が想定していないであろう極めて不適切な運用を行うのが日本の警察です。これらのケースは極めて無理な運用であり、特に後者などは「日本にウイルス作成罪は存在しないが、被疑者は何としても罰したい」という魂胆が明らかです。私はウイルス作者などを弁護する気は全くありませんが、これは法の運用として間違っています。
 単純所持が違法化されたとしても、違法画像を添付した悪質なスパムメールが了解もなく送りつけられてくるなど、不可抗力の行為は違法とならないものとされていますが、上記のような法運用がなされるようではこれも怪しいです。明らかに法に触れない状況であったとしても、どのような曲解の上で逮捕されるか分かったものではありません。単純所持の規制に反対する気はありませんが、警察などの権力がいかなるでっち上げを行うか分からない以上、現時点で賛成するには少々難しいものがあります。
 ましてや、アニメなどの創作物規制は論外といわなくてはなりません。創作物には被害者が存在しない以上、写真や画像の氾濫による二次被害は存在しませんので、問題は「その創作物を規制する意味はあるか」、すなわち「それによって児童への犯罪が増えるか」の一点となります。もし犯罪率が大幅に増えているようなら、社会の安全のために規制することはやむを得ません。ところが、規制推進側がそのようなデータを示したという話は、今までただの1度たりとも聞いたことがありません。有意なデータを示せば確実に支持が得られるにもかかわらず、なぜ推進側はそれをしようとしないのでしょうか。
 これはアニメや児童ポルノ問題以外にも当てはまります。例えば少年犯罪で必ず槍玉に挙げられるのがマンガやゲームですが、もし殺人のあるマンガやゲームを体験した人が1割でも殺人を犯すなら、日本全国で膨大な量の殺人が発生するであろうことは想像に難くありません。一方、自殺サイト殺人事件の犯人は小説に影響されていますが、小説は青少年に悪影響があるから規制しろなどという主張がなされた例は見たことがありません
 事件の中にはアニメやゲーム、マンガに影響されていたり、または影響されたことを自ら認める犯人も存在しますが、もしこれらがなかったらその犯人は犯罪を犯さなかったと誰に言えるのでしょうか。また、児童ポルノの創作物に関しては、それの存在によって実際の犯罪が減ると主張する向きもあります。しかし、前述の通り規制推進側が犯罪増加を裏付けるデータを出したことは1度としてなく、これらの真偽を分析することすらできません。ちなみに少年犯罪は(絶対数・人口比ともに)1980年代前半をピークに減っていることが、誰でも自由に見ることができる「犯罪白書」で述べられています。あの「ファミコン」が世に出たのが1983年ですが、皮肉なことにその辺りから犯罪の減少が始まります。
 警察が恣意的な法運用をする恐れさえなければ、被害者が存在する児童ポルノの単純所持を取り締まることは理解できます。被害者が二次被害を受けることが避けられない上、需要があることで被害者が増える可能性もあり、取り締まる理由としては十分です。しかし、創作物には被害者が存在せず、社会を危険にするという証明もありません。データすら示されないものに論じる価値などありません。それでも規制が必要というなら、「ゲーム脳」のようなインチキ学説ではなく、追試可能で反証可能性を備えたデータを即刻提示しなければなりません。

 本日はHaskellを離れまして、Schemeの「継続」について。これは非常に難解な概念らしく、Common Lispの経験があればSchemeは即座に理解できるそうですが、継続だけは理解が難しいようです。ましてや、Common Lispの経験すらない私に理解できるのでしょうか。
 まずはGoogleで探してみましょう。きっと参考になるサイトが多く存在するはずです。結果、色々とサイトは見つかりましたが、さすがに様々なサイトから引用することはできませんから、Wikipediaより。

「プログラミングにおいてある計算過程のある瞬間における、その過程の未来全体(デフォルト)を表すもの」
「計算過程の実行スナップショットと説明される」
「継続は、実行中のどんな計算機プログラムにも存在する」
「しかし継続の概念は、ほとんどの (Scheme や Ruby を除く) プログラミング言語では明示的に扱われていない」

 さっぱり意味不明です。他のサイトの説明も似たり寄ったりで、

(+ (+ 5 10) 15)の処理は、5に10を足した結果を取得し、それに15を足して返す処理。5に10を加算し、その後15を加算するという処理自体が継続であり、C言語などほぼすべての言語に存在するが、それを明示的に扱うのがSchemeの継続である。

 などと、これまたさっぱり意味不明な解説がなされていたりします。
 それでは、これは一体何に使うのでしょうか。Wikibooksによれば、

「大域脱出、コルーチン、疑似マルチタスク、バックトラックといった特殊な制御を必要とするプログラムを効率的に記述することができる」

 そうです。Wikipediaにもエスケープgotoの代わりになるなどと書かれていました。また、例外処理と同じこともできるそうです。まとめると、

・継続とはその過程の未来全体を表すもの
・継続はあらゆるプログラムに存在する
・Schemeではそれが明示的に扱われているに過ぎない
・バックトラック制御ができる
・エスケープgotoができる
・例外処理ができる

 もはや意味不明です。何がどうつながっているのでしょうか。
 いつものパターンからして、このようなものは実際にはさほど難しくないにもかかわらず、なぜか皆々様でやたらややこしく書き立てる性質にありますので、実践あるのみです。とにかく適当なプログラムを書いてみるとしましょう。
 まずは継続の使い方から。継続を生成する際にはcall-with-current-continuation関数を用い、引数として「引数を1つ取る関数」を取るそうです。関数なら何でも構わないようですが、大抵はラムダが使われています。そして、この引数には継続関連のデータが渡されているようです。これだけ分かればサンプルプログラムを組むことができるでしょう。
 関数call-with-current-continuationは非常に長いため、call/ccと略されることが多いようです。最初に定義しておきましょう。
(define call/cc call-with-current-continuation)
 まずは特別な計算を行わないラムダを定義してみます。
(call/cc 
	(lambda (c) 
		10
	)
)
 見ての通りですが、結果は「10」です。
 次に引数を使ってみましょう。この引数はどうやら関数のようです。
(call/cc 
	(lambda (c) 
		(begin
			(c 20)
			10
		)
	)
)
 今度は「20」でした。どうやらcにはCやJavaでいうreturnの効能があるようです。
 しかし、これでは継続の意味がありません。call/ccを呼び出したラムダの中でさらにcall/ccを呼び出し、挙動を試してみましょう。
(call/cc 
	(lambda (c1)
		(begin
			(call/cc
				(lambda (c2)
					(begin
						(c1 -1)
						(display "以下は不実行")
						10
					)
				)
			)
			20
		)
	)
)
 このように書くと、c1を呼び出した時点ですべてのラムダを抜けて制御が戻ることが分かります。c1呼び出しの時点で抜けてしまうため、display文は実行されません。言うまでもなく「-1」が得られます。
 つまり、継続とは関数にタグ付けをしておいて、タグ付きreturnで制御を戻すようなものと考えられそうです。以下にC風の擬似コードを書いてみます。
int lambda1(){
	int lambda2(){
		return lambda1 -1;
		printf("以下は実行されない");
		return 10;
	}
	return 20;
}
 何のことはありません。あれほど難しく書かれていた「継続」とは、ただこれだけのものなのです。ちなみに、人によっては上記の例を
int lambda1(){
	int lambda2(){
		goto BANK;
		printf("以下は実行されない");
		return 10;
	}
	return 20;
}
BANK:
 このように考えたりしているようです(ただしgotoでは戻り値を返せない点に注意)。「関数の終わりまで処理を持っていって継続する」という理屈だそうです。
 それはそうと、Wikipediaのこの記述は引っかかります。

「しかし継続の概念は、ほとんどの (Scheme や Ruby を除く) プログラミング言語では明示的に扱われていない」

 Rubyでcall/ccを実装した人がいるらしいとは聞いたことがあります。しかし、Rubyでも継続は実装できるのでしょうが、Rubyで明示的に継続が扱われているとは初耳です。
 ところで、以前から妙に気になっているのですが、日本語版Wikipediaは何かにつけ必ずRubyを持ち出してきます。Ruby自体はそれほど飛びぬけてメジャーな言語ではありませんし、Ruby on Railsがなければ今でも外国ではほとんど知られていなかったと考えるべきでしょう。欧米ではPythonの方がずっとメジャーですし、日本にもPython使いは多く存在します。Wikipediaの性質からすれば、より有名なPythonの方をより重く取り上げるのが自然です。
 考えられる原因は1つ、同族意識です。日本発の言語であるため日本で多く使われており、日本人には他の言語よりRubyの方がよく知られているのか、日本発の言語だからPythonなどを知っていてもRubyを優先的に取り上げるのかは分かりませんが、どうも気のせいではないほどRubyが取り上げられている気がしてなりません。一方、私はオリンピックでもワールドカップでも日本を応援しない筋金入りの無同族意識者ですので、これに違和感を覚えたとしても不思議ではありません。
 正直なところ、私はRubyが嫌いではないにせよ苦手です。最も苦手なのはVB.NETで、その次に苦手なのがRubyです。理由は良く分かりませんが、どちらも書いているとなぜかイライラしてきます。VBはループ構文を未だに覚え切れませんし、構文をミスしてイライラすることが多いのですが、Rubyは別に失敗してもいないのに書いているだけでストレスです。冗長なのが理由ではとも考えましたが、COBOLはなぜかRubyほどではありません。今までブログで取り上げただけでも両手で数え切れないほど様々な言語を使っているはずなのですが、書くだけでイライラするのはVBとRubyだけです。GroovyのクロージャもLispやHaskellのラムダも平気ですから、ブロック付きメソッド呼び出しが悪いわけでもなさそうですし、スクリプトならPHPでオブジェクト指向を書かない限りはPerlもPHPもPythonも平気ですから、不思議でなりません。
 私は決してRubyを始める前からRubyが苦手なわけではありませんし、理由もなく言語を嫌うこともありません。おそらく無意識のうちに言語仕様の問題点なり特異な部分なりの影響を受けているのでしょう。この辺りはC++やPerlなどといった言語が好きになれない人とおそらく同じです。
 しかし、Wikipediaの記述に関しては、苦手意識は極力封印して判断しているにもかかわらず、やはりRubyが妙に多い気がしてなりません。今回も

「 (Scheme や Ruby を除く) プログラミング言語では明示的に扱われていない」

 などという具合にしっかりRubyのみが入っています。Common Lispでもマクロの組み方次第でcall/ccが使えるらしいのですが、含まれていません。「明示的に」扱われていなければならないというなら、Common LispなりJavaなりPHPなりの言語の標準パッケージに継続機能が組み込まれたら、これは「明示的に」扱われたとみなすのでしょうか。
 こうなれば仕方ありません。call/ccをC++で実装することができれば、(継続自体が主要な言語使用の一部であるSchemeはともかく)Rubyの専売特許ということにはならないはずです。ここはひとつ、C++で書いてみようではありませんか。
 とはいえ、クリアすべき問題は山のようにあります。call/ccをC++で書こうなどと考えた人はそうそういないのではないでしょうか。片付けなければならない問題と私の解決法を以下に示します。

1.複数の関数から一気に抜ける構文が、抜ける途中の関数に何ら細工をすることなく必要。また、関数を一気に抜ける際には、call/ccによって呼び出した大本の関数の返り値型が必要であるため、そもそもreturnを繰り返しつないで値を返す手法は通用しない。

 C++使いの方には、これの厳しさがご理解いただけるでしょう。C++では関数の中身をこちらで書き換えて細工することなどできませんし、できたとしても返り値の型が違えばアウトです。
std::string b(){
	// 普通に返すなら std::string で構わないとして...
	return std::string("");

	// a() まで一気に抜けたい場合はどうする?
	// ここで何とかして int を返さなくてはならないが...
}
int a(){
	return b();
}
 八方ふさがりに見えますが、実はこれを回避する方法があります。一気に複数の関数を抜けることができ、しかも型をreturnで返す必要がないその方法とは、言うまでもなく例外です。

2.Schemeではラムダの第一引数を使って、例えば変数名がcであるなら「(c 10)」と書くことで値を返せたが、C++ではどうすべきか。c.call(10)でも動くには動くものの、できればSchemeに似た構文が欲しいところ。

 関数オブジェクトです。これしかありません。

3.call/cc呼び出し内でcall/ccを呼び出し、しかもいずれかの変数を利用していずれかのcall/ccまで戻ろうとした場合、正しく任意のcall/ccに戻れなければならない。

 何も考えずに例外処理をしていると、1か所のcatchで全部キャッチされてしまいます。これでは任意の場所に処理を戻すことができません。これでは困りますので、ネストレベルを保管するスタティック変数を用意しました。Thread指定をしてやればマルチスレッドでも安全です。

4.型に困る。call/ccで呼び出した関数の返り値がintなら、その関数から呼ばれた関数の返り値がstd::stringだろうがstd::vectorだろうが、call/ccに戻る場合に渡す値はintでなくてはならない。

 テンプレートを使うしかないでしょう。

 問題はこの程度でしょうか。以下に私の実装を示します。
#define callcc(T,x,f); T x;\
	try{\
		x = f(CallCCObject<T>(CallCCIDGen::increment()));\
		CallCCIDGen::decrement();\
	}catch(CallCCNotify<T> &callcc_notify_exception_handler){\
		if(CallCCIDGen::decrement() == \
			callcc_notify_exception_handler.get_id()){\
			x = callcc_notify_exception_handler.get();\
		}else{\
			throw;\
		}\
	}catch(...){\
		CallCCIDGen::decrement();\
		throw;\
	}
#define callcc1(T,x,f,arg); T x;\
	try{\
		x = f(CallCCObject<T>(CallCCIDGen::increment()) , arg);\
		CallCCIDGen::decrement();\
	}catch(CallCCNotify<T> &callcc_notify_exception_handler){\
		if(CallCCIDGen::decrement() == \
			callcc_notify_exception_handler.get_id()){\
			x = callcc_notify_exception_handler.get();\
		}else{\
			throw;\
		}\
	}catch(...){\
		CallCCIDGen::decrement();\
		throw;\
	}
#define callcc2(T,x,f,arg1,arg2); T x;\
	try{\
		x = f(CallCCObject<T>(CallCCIDGen::increment()) , \
			arg1 , arg2);\
		CallCCIDGen::decrement();\
	}catch(CallCCNotify<T> &callcc_notify_exception_handler){\
		if(CallCCIDGen::decrement() == \
			callcc_notify_exception_handler.get_id()){\
			x = callcc_notify_exception_handler.get();\
		}else{\
			throw;\
		}\
	}catch(...){\
		CallCCIDGen::decrement();\
		throw;\
	}
#define callcc3(T,x,f,arg1,arg2,arg3); T x;\
	try{\
		x = f(CallCCObject<T>(CallCCIDGen::increment()) , \
			arg1 , arg2 , arg3);\
		CallCCIDGen::decrement();\
	}catch(CallCCNotify<T> &callcc_notify_exception_handler){\
		if(CallCCIDGen::decrement() == \
			callcc_notify_exception_handler.get_id()){\
			x = callcc_notify_exception_handler.get();\
		}else{\
			throw;\
		}\
	}catch(...){\
		CallCCIDGen::decrement();\
		throw;\
	}
#define callcca(T,x,f,args); T x;\
	try{\
		x = f args;\
		CallCCIDGen::decrement();\
	}catch(CallCCNotify<T> &callcc_notify_exception_handler){\
		if(CallCCIDGen::decrement() == \
			callcc_notify_exception_handler.get_id()){\
			x = callcc_notify_exception_handler.get();\
		}else{\
			throw;\
		}\
	}catch(...){\
		CallCCIDGen::decrement();\
		throw;\
	}
#define callwith(T) CallCCObject<T>(CallCCIDGen::increment()) ,
#define in
#define callarg(T) CallCCObject<T>(CallCCIDGen::increment())
#define calltype(T) CallCCObject<T>
#define callvar(T,v) CallCCObject<T> v

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>

#define Thread  __declspec( thread )

class CallCCIDGen{
	Thread static int id;
public:
	static int increment(){
		int old = id;
		id ++;
		return old;
	}
	static int decrement(){
		id --;
		return id;
	}
	static int get(){
		return id;
	}
};
int CallCCIDGen::id = 0;

template<class T> class CallCCObject{
	int id;
public:
	CallCCObject(int i){
		id = i;
	}
	void operator()(const T &t){
		throw CallCCNotify<T>(t , id);
	}
};

template<class T> class CallCCNotify{
	T value;
	int id;
public:
	CallCCNotify(const T &t , int i){
		value = t;
		id = i;
	}
	T& get(){
		return value;
	}
	int get_id(){
		return id;
	}
};

/*
callcc の使い方

I.callcc で呼び出す関数を書く
(これは Scheme ではラムダで書くことが多い)
引数に callvar(type , varname)、あるいは
calltype(type) varname と記述したものを1つ用いる
type は返り値と同じか、返り値と代入互換の関係にあること

以下は等価
int funcname(callvar(int , c)){
	// ...
}
int funcname(calltype(int) c){
	// ...
}

関数は他の引数を取ることができる
引数の個数や型は自由
例:
int funcname(calltype(int) c , int a , int b , ...){
	// ...
}

callvar/calltype 変数に type 型の値を渡すと
その場で処理を終了する
例:
int funcname(calltype(int) c , int a , int b , ...){
	c(100);	// 100 を返して処理終了
	printf("ここから下は実行されない");
	return 10;
}

II.callcc 系関数を使って関数をコールする

*callcc(type , var , function);
引数なしの(callvar/calltype のみを取る)関数を呼び出す
type で返り値の型、function で処理する関数の名前を指定
変数 var に結果が格納される
例:
int funcname(calltype(int) c){
	// ...
}
void main(){
	callcc(int , var , funcname);
	printf("%d\n" , var);
}

*callcc1(type , var , function , arg);
callvar/calltype 以外に引数を1つ取る関数を呼び出す
callvar/calltype は先頭に置く必要がある
例:
int funcname(calltype(int) c , int argument){
	// ...
}
void main(){
	callcc1(int , var , funcname , 10);
	printf("%d\n" , var);
}

*callcc2,callcc3
callcc1 の引数が2つ及び3つになるだけで、他に違いはない

*callcca
引数の数及び callvar/calltype の位置が自由な callcc
以下に様々な例を示す

A.引数が0個(callvar/calltype を除く。以下同様)の場合
callcca(int , var , zeroargsfunction , (callarg(int)));

B.引数が1個の場合
callcca(int , var , oneargsfunction , (callwith(int) in "somearg"));
または in を省略して
callcca(int , var , oneargsfunction , (callwith(int) "somearg"));

C.引数が1個で callvar/calltype を後置する場合
callcca(int , var , oneargsfunction , ("somearg" , callarg(int)));

D.引数が2個の場合
callcca(double , var , twoargsfunction , (callwith(double) in 1 , 2));

E.引数が5個の場合
callcca(short , var , fiveargsfunction , 
	(callwith(short) in 1 , 2 , 3 , 4 , 5));

F.引数が5個で、callvar/calltype を1つ目の引数の後に書いた関数を呼ぶ場合
callcca(short , var , fiveargsfunction , 
	(1 , callarg(int) , 2 , 3 , 4 , 5));

※callwith または callarg の型は、callcca の型と同じにしてください
自動的にこれを行わないのは C++ 言語の仕様の限界によります

※複数の関数からの脱出について
関数 a , b , c , d があるとして...
main から callcc で a を呼び、そこから b を呼び、
そこから c を呼び、そこから d を呼び、
そこで継続を呼び出して処理を戻すことももちろんできる
それをする場合は、次の関数に calltype 変数を渡すようにする
ここでは簡単に main -> a -> b での b からの脱出を考える
void main(){
	callcc(int , var , a);
	printf("%d\n" , var);
}
int a(calltype(int) cc){
	return b(cc);
}
int b(calltype(int) cc){
	cc(10);	// 一気に main() 関数まで移動する
	return 0;	// ここは呼ばれない
}
*/
 構文がややC++らしくありませんが、これでも何とか動いてしまいます。C++にラムダは存在しないため、呼び出すべき関数はcalltype(type)型の引数を持つ関数として実装します。callccは引数を(calltypeしか)取りませんが、callcc1で1つの引数を、callcc2で2つの引数を、callcc3で3つの引数を渡せる他、callccaを使用すれば引数をいくらでも渡すことができます。
int func(calltype(int) cc , int a , int b , int c , int d , int e){
	cc(...);	// これを呼び出すと即座に抜ける
	return ...;
}

// ...

callcca(int , var , func , 
	(callwith(int) in 1 , 2 , 3 , 4 , 5));
// int var が宣言され、その中に func の結果が格納される
printf("%d" , var);
 また、クラスのメンバ関数を呼ぶこともできます。
callcca(int , var , obj.func);
 以下、様々な動作を試してみたソースです。
int sub(callvar(int , c)){
	c(20);
	return 10;
}

int suba(calltype(int) c , int a){
	c(a);
	return 10;
}

int subb(calltype(int) c , int x , int y , int z){
	c(x + y + z);
	return 0;
}

double dividing(calltype(double) cc , double a , double b){
	if(b == 0)
		cc(a);
	return a / b;
}

double proc(calltype(double) cc , double a , double b , double c){
	return dividing(cc , a * b , c);
}

double divzero(calltype(double) cc){
	double zero = 0;
	cc(1.0);
	return 1.0 / zero;
}

char* concat16(calltype(char*) cc , char *a , int ib , char *buf){
	char b[16];
	itoa(ib , b , 10);
	if(strlen(a) + strlen(b) >= 16)
		cc("");

	strcpy(buf , a);
	strcat(buf , b);
	return buf;
}

int c(calltype(int) cc){
	cc(100);
	return 0;
}
int b(calltype(int) cc){
	return c(cc);
}
int a(calltype(int) cc){
	return b(cc);
}

int multicc2(calltype(int) cc2 , calltype(int) cc1 , int endnum){
	if(endnum == 1)
		cc1(1);
	if(endnum == 2)
		cc2(1);
	return 0;
}

int multicc1(calltype(int) cc1 , int endnum){
	callcc2(int , var , multicc2 , cc1 , endnum);
	return var + 10;
}

// callcc を複数使っていても、それぞれ別の型を返すことができる
struct test1{
	char *label;
	test1(){
		label = "";
	}
	test1(char *l){
		label = l;
	}
};
struct test2{};
test2 t2(calltype(test2) cc2 , calltype(test1) cc1 , int endnum){
	if(endnum == 1)
		cc1(test1("t2 からの cc1 コールによる返り値"));
	if(endnum == 2)
		cc2(test2());
	return test2();
}
test1 t1(calltype(test1) cc1 , int endnum){
	callcc2(test2 , var , t2 , cc1 , endnum);
	return test1("t1 からの return による返り値");
}

int multicca2(calltype(int) cc2 , calltype(int) cc1 , int endnum){
	if(endnum == 1)
		cc1(1);
	if(endnum == 2)
		cc2(1);
	return 0;
}

int multicca1(calltype(int) cc1 , int endnum){
	callcca(int , var , multicc2 , (callwith(int) in cc1 , endnum));
	return var + 10;
}

class cclass{
public:
	bool flag;
	char* call(calltype(char*) cc){
		if(flag)
			cc("flag が true");
		return "flag が false";
	}
};

void main(){
	// シンプルな callcc , callcc1 , callcca の使い方
	callcc(int , x , sub);
	callcc1(int , y , suba , 30);
	callcca(int , z , subb , (callwith(int) in 10 , 20 , 30));
	printf("%d,%d,%d\n" , x , y , z);

	// 正常動作版
	{
		callcca(double , n , proc , 
			(callwith(double) in 10.0 , 5.0 , 10.0));
		printf("%f\n" , n);
	}

	// Call/CC で抜ける処理
	{
		callcca(double , n , proc , 
			(callwith(double) in 10.0 , 5.0 , 0.0));
		printf("%f\n" , n);
	}

	// ゼロ除算の前に抜ける処理
	{
		callcc(double , n , divzero);
		printf("%f\n" , n);
	}

	// 文字列連結関数
	char buf[16];
	{
		callcc3(char* , str , concat16 , 
			"under bytes " , 16 , buf);
		printf("%s\n" , str);
	}

	{
		callcc3(char* , str , concat16 , 
			"this string over bytes " , 20 , buf);
		printf("%s\n" , str);
	}

	// 複数の関数から一気に抜ける
	{
		callcc(int , var , a);
		printf("%d\n" , var);
	}

	// callcc のネスト
	// multicc 関数を正常終了
	{
		callcc1(int , var , multicc1 , 0);
		printf("%d\n" , var);
	}

	// multicc2 で multicc1 の callcc に戻る
	{
		callcc1(int , var , multicc1 , 2);
		printf("%d\n" , var);
	}

	// multicc2 から直接ここに制御を戻す
	// multicc2 で継続がコールされた時点で
	// multicc1 の残りの処理は全部無視される
	{
		callcc1(int , var , multicc1 , 1);
		printf("%d\n" , var);
	}

	// callcc のネスト(型違い版)
	{
		callcc1(test1 , var , t1 , 0);
		printf("%s\n" , var.label);
	}

	{
		callcc1(test1 , var , t1 , 2);
		printf("%s\n" , var.label);
	}

	{
		callcc1(test1 , var , t1 , 1);
		printf("%s\n" , var.label);
	}

	// クラスのメソッドを呼び出す
	cclass cls;
	{
		cls.flag = true;
		callcc(char* , str , cls.call);
		printf("%s\n" , str);
	}

	{
		cls.flag = false;
		callcc(char* , str , cls.call);
		printf("%s\n" , str);
	}
}
 この通り、(強引ではありますが)C++でも継続が実装できてしまいました。継続はSchemeやRubyの専売特許ではないことが分かります。継続の概念を深く理解するには、やはり自分で実装してみるのが最も確実です。
カテゴリ [開発魔法][社会問題][経済・知的財産] [トラックバック 0][コメント 0]

イス取りゲーム
2008/04/08(Tue)23:30:04
 日銀の総裁問題で、民主党は白川氏の総裁格上げを容認したものの、渡辺氏が副総裁となることについては不同意を決定しました。与党が白川人事のみを受け入れれば、とりあえず総裁空席の状態は回避されることになります。
 日銀の人事に関しては、最近は「たすきがけ人事」(財務省と日銀出身者が交互に総裁ポストに就任する習慣)の事実もちらほら報道されるようになってきており、おそらく「日銀の独立性」の重要性も以前に比べれば多少は認識されてきたことでしょう。世論調査を見ても、日銀総裁問題について「政府に責任がある」と考える人は非常に多く、民主党に全責任を押し付けた上で財政と金融の分離に疑念のある人事を通そうという政府や一部マスコミの目論見が完全に失敗していることが分かります。
 無論、民主党の対応も100点満点とはいきません。日銀の独立性が重要であることはここでも繰り返し述べていますが、民主党の反対は日銀の独立性を担保するためというより、小沢氏による「反対のための反対」の道具に使われた印象は否めません。反対の理由はどうあれ、主張自体は決して間違ったものではありませんが、あまり良い印象を持たれていないことは明らかです。
 経済の問題は非常に難しいため、インサイダーや証券などの犯罪にせよ、金融と財政の分離にせよ、一見すると何が問題であるのか分からない例が多いのですが、だからこそ民主党は反対の説明責任を十分に果たす必要がありました。現状でなされている説明はとても十分なものとはいえず、問題はあまり深く理解されていません。また、今回の例でも党内から渡辺副総裁人事に賛成する声が出るなど、民主党が一枚岩ではない印象も受け、党内がガタガタなせいで迷走振りがさらに印象付けられています。
 今回、民主党が白川氏格上げを了承したのは妥当な決定でしょう。白川氏には民主党が主張するような問題がない以上、これに同意しないのは単なる反対のための反対であって、それをする正当性は全くありませんので、おそらく世論の支持は全く得られなかったでしょう。また、実際に白川氏は財務(大蔵)官であるなどということはなく、独立性の点からも妥当な人事です。さらに総裁の空席も回避できます。
 一方、政府側の行動にも非常に多くの疑問があります。あえて民主党に反対される可能性が高い人事をあてつけのようにぶつけてきており、民主党が「反対のための反対」であるなら、政府は「反対されるための行動」を取っています。前述の通り経済の問題は難しい上、民主党は十分な説明を行っておらず、しかもマスコミの多くも日銀の独立性の重要さについて切り込んでいませんので、民主党の反対行動を印象付ければ世論の批判をかわせるとの魂胆なのでしょうが、このような行動を取っても混乱が深まるばかりです。
 実際にこれまでの人事案を見ても、武藤氏、田波氏、渡辺氏とすべて財務(大蔵)人事です。政府が彼らを純粋に適任者であると考えたのか、財務省出身であるためコントロールまたは「たすきがけ人事」ができるという民主党が指摘しているような下心があったのかは分かりませんが、政府としてはこれらの人事を通したかったのであろうことは明らかです。しかし、民主党が基準を示して反対している以上、次善の策として財務省以外から優秀な人材を連れてくるのが混乱回避のために最も適切な手段であったことは言うまでもありません。政府・与党にはそれができたにもかかわらず、あえてそれをしなかったのです。
 しかし、これでとりあえず総裁の空席は埋まりましたし、副総裁についても政府はそろそろ現実的な人事を出してくるころでしょう。民主党としても問題のない人事であればほぼ確実に通すはずですから、この程度の混乱で日銀の独立性が担保できるのであれば十分な収穫でしょう。
 日銀の独立性が侵される危険は、渡辺氏の所信聴取時の民主党議員の質問にも表れています。同党の議員が国債に対する質問をしたところ、渡辺氏は「国債のために金利を下げる政策運営はしない」と言い切りましたが、つまり国としては金利が上がって国債の利払いが増えれば苦しくなり、際限なく国債を発行するのも難しくなるため、政府としては金利の上昇を嫌う場合がありますが、日銀には政府のそのような干渉を跳ね除ける力が要求されるわけです。
 また、以前の記事で述べたことをもう1度取り上げておくなら、先に量的緩和やゼロ金利が解除となった際、政府・与党の一部はこれに対して強い反発を表明し、「法案を提出する」ことまで口にして日銀を恫喝しました。財務(大蔵)省出身では圧力を退けられないと言い切ることはできませんが、このような恫喝にも屈しないことを担保できる人事といえば、やはり財務省出身でないことが望ましいのです。
 今回の総裁騒動について、諸外国からの日本の信頼が失墜し、日本の金融が意外にもろいことが明らかになったと評する向きもありますが、むしろこの程度の混乱で日銀の独立性が話題に上り、しかもそれがより強く担保されるような人事がなされ、さらに「たすきがけ人事」が一掃されたのは大きな成果であると考えるべきでしょう。

 このところHaskell、COBOL、F#、Scheme、Lispに挑戦してみていますが、とりあえずモナドからParsecまでおおむね使えるようになったHaskellを。私にとっては初めての関数型言語です。
 関数型言語には色々ありますが、その中からあえてHaskellを選んだのは、Perl 6のインタプリタであるPugsがHaskellで書かれているらしいことが分かったためです。Pugsは不完全なインタプリタではありますが、Perl 6の構文はそこそこ動作します。どうせ関数型言語を学ぶなら、それなりのものが書けるという実績のある言語を選ぶ方が良いに決まっています。
 Haskellの特徴は以下の通りです。

・参照透過的である
 関数に同じ引数を与えると、その関数は必ず同じ値を返すことが保証されています。CやPerlなどの一般的な言語では変数にデータを代入しますが、参照透過的な言語においては値の代入は許されません。1度生成された物の値が変わることは許されないのです。したがって、例えばC++やJavaでよくある
for(int i = 0; i < size; i++){
	...
}
 このようなコードはあり得ません。iの値が変更され、参照透過性を破壊しているためです。

・遅延評価である
 関数やリストは評価が必要になった時に評価されます。評価が不要なものは最後まで評価されません。遅延評価の弱点として、何がどのような順番で実際に評価されるのかが分からないことがありますが、Haskellは参照透過的な言語であるため、同じ引数を与えた関数は必ず同じ値を返すことが保証されており、何がどの順番で評価されようと関係ありません。
 したがって、次のようなコードは動作します。
inflist = [1..]	-- 1から始まる無限の長さを持つリスト
main = take 5 inflist	-- リストの頭から5個の値を取り出す
 また、関数は必要になるまで評価されないため、
f a = 10	-- 引数を1つ取って10を返す関数 f
main = f someFunction	-- someFunction は何らかの関数であるものとする
 someFunctionは評価されません。仮にsomeFunctionが必ずエラーを投げて処理を終了するようなものであったとしても、関数f内ではこれを評価する必要がないため評価しません。

・モナド
 上記2つはHaskellの長所でも短所でもあります。代入ができなければ変数の変化を追うことは困難ですし、色々と不便もあります。また、IO処理は参照透過や遅延評価と相性が悪いものとされています。

1.参照透過性とIO処理
 C言語のgetsやscanf、C++のcin、JavaのSystem.in.read、C#のConsole.ReadLineなどはユーザーの文字入力を促し、何らかの方法でその文字列を返します。つまり、同じ関数を同じ引数で呼び出したとしても、ユーザーの入力によって動作が違ってしまうのです。これは参照透過性を破壊します。同じように参照透過性を破壊するものとして、ファイルの入力や日時の取得、ランダム処理などがあります。

2.遅延評価とIO処理
 参照透過性が守られている限り、関数はいつ評価しようと同じでした。しかし、IO処理で処理の順番が分からないのは困ります。順番にメッセージを表示するはずが、表示順が逆転してしまうかもしれません。また、ユーザーの入力を受け取って何らかの出力処理を行うような場合、出力が入力の前に来るのは非常に困ります。

 これを解消するのがモナドです。モナドは今のところHaskellにしか見られない特徴です(WikipediaによればF#にもあるらしいのですが、詳細や事実は不明です)。しかし、このモナドがまたHaskellの鬼門と呼ばれているもので、嫌になることうけあいです。

 以上がHaskellの特徴です。Haskellといえばモナド、モナドといえばHaskellなのですが、これを最初から扱うのは厳しすぎますので、ごく基本的な構文の覚え書きを。
 ひとまず基本の関数定義から。
f = 10
 これで「10を返す関数」を定義します。決してfに10を代入するのではありません。Haskellには代入がないため、=記号は関数定義に用いられます。
 関数を書くのであれば、プロトタイプ宣言を書いておく方が分かりやすいでしょう。
f :: Integer
f = 10
 関数は引数を取ることができます。
f :: Integer -> Integer
f x = x
 これは整数を取ってその整数を返す関数です。
 しかし、このような関数は整数以外にも使えるはずです。C++なら
template<class T> T f(T x){
	return x;
}
 などと書くところでしょう。何とも恐ろしいことに、Haskellはこのような機構を標準装備しています。
f :: a -> a
f x = x
 これだけです。aが何型であるかは分かりませんが、何らかの型を取って同じ型を返す関数になります。
 ちなみに、このプロトタイプを
f :: a -> b
 このように書くと、何らかの型を取って違う型を返す関数になります。ただし、aとbが同じ型を表す(この場合は何らかの型を取って同じ型を返す)ことも許されています。
 関数は2つ以上の引数を取るように表記できます。
plus :: Integer -> Integer -> Integer
plus a b = a + b
main = plus 2 3
 しかし、2つ以上の引数を取る関数というものは存在しません。2つ以上の引数を取る構文は、上記なら「Integerを取って「Integerを取ってIntegerを返す関数」を返す関数」を実行した後に「Integerを取ってIntegerを返す関数」を実行する糖衣構文に過ぎません。
 ここで重要になるのが「カリー化」の概念です。Haskell自体が論理学者「ハスケル・ブルックス・カリー」にちなんで名づけられたもので、「カリー化」の名称もこの人にちなんだものです。カリー化を使うと「関数の一部に引数を与えた新しい関数を返す」ことができます。
 方法は簡単、関数に一部だけ引数を与えるだけです。
-- 2つの引数を取って値を返す関数
plus :: Integer -> Integer -> Integer
plus a b = a + b

-- plus の最初の引数に 10 を与えてカリー化
-- これで Integer を取って Integer を返す関数のできあがり
plus10 :: Integer -> Integer
plus10 = plus 10

-- このように書ける
main = plus10 5

-- または plus10 の定義を省略して
main = (plus 10) 5
 Haskellの関数はファーストクラスであるため、変数であるかのように引数として渡したり返り値にしたりすることができます。そればかりか、変数自体が「変数に見えるもの」であって、その実体は特定の値を返す関数です。
 その時にしか使わない関数を用いるには、ラムダがよく用いられます。
-- 整数と(整数を取って整数を返す関数)を取って整数を返す関数
-- 何らかの整数に対してユーザー定義の計算を実行できる
userDefinedCalc :: Integer -> (Integer -> Integer) -> Integer
userDefinedCalc a f = f a

-- (\x -> ...) がラムダ記法
-- 引数を1つ取って何らかの値を返す匿名関数が作られる
-- ここでは2乗の処理をしていることが分かる
main = userDefinedCalc 20 (\x -> x * x)
 関数を取る関数を「高階関数」と呼ぶそうです。
 後はクラス(C++などのクラスとは全く概念が違う存在)やリスト内包、letやwhereによる局所関数、タプルなど取り上げるべき概念は山のようにありますが、今後取り上げるかは不明です。これらを覚え書きするにしては他に優れた解説が山のようにありますし、Haskellといえばモナドですから、覚え書きならこれを中心にする方が適当でしょう。
 以下、数学の分野である「圏論」のモナドについての解説です。

 数学には「圏論」(カテゴリー・セオリー)なる学問があります。Haskellのモナドを学ぶために圏論及びそのモナドを学ぶ必要は必ずしもありませんが、Haskellで用いられるモナドは圏論のモナドから拝借したものであるため、圏論が分かればHaskellの理解も深まることは間違いありません。ちなみに、「モナド」は「モノイド」と「トライアド」の組み合わせであって、ライプニッツのモナドとは関係ありません。
 まずはWikipediaの圏論モナドを調べてみましょう。曰く、モナドとは「関連する2つの自然変換を伴う(自己)関手」とのことです。以下、恒等関手だの恒等変換だのと意味不明なことがひたすら書いてあります。このような文章を見て意味が理解できる人は存在するのでしょうか
 残念ながら、Googleでインターネットを検索してみても、分かりやすい日本語の資料はほとんど存在しないのが実情です。かといって、Wikipediaに代表されるような数学者向けの高等な説明は理解できませんし、圏論の本となると敷居が高すぎます。しかし、「理系ではないのでモナドの習得はあきらめます」などと称して全部放り出すのも面白くありません。
 そこで、私が独自に習得した圏論についてまとめておくことにします。例によって正確性は保証しませんが、雰囲気はつかめるでしょう。

騎士サーラ「さて、イリアスさん。突然ですが、カテゴリーとは何でしょう」
魔道士イリアス「カテゴリー?えーと、ブログの記事の分類なんかでよく見かけるわね。開発記とか、社会問題とか、徒然(トゼン)日記とかに分けてあって・・・」
騎士サーラ「はい、確かにそれもカテゴリーなのですが、カテゴリー論の意味はもう少しスケールが大きいものです」
魔道士イリアス「どういう意味?」
騎士サーラ「イリアスさん、開発言語はご存知ですね?」
魔道士イリアス「C、C++、Java、Perl、PHP、SQL、XQuery辺りの魔法は飛ばせるけど?」
騎士サーラ「そうした言語はすべて、プログラム言語のカテゴリに入ります」
魔道士イリアス「当たり前じゃないの?」
騎士サーラ「そればかりか、世の物事の多くはカテゴリーなのです。1や64は整数のカテゴリーのメンバーとなりますし、文字であればアルファベット、ひらがな、漢字などのカテゴリーに入るでしょう」
魔道士イリアス「それがカテゴリー論?」
騎士サーラ「ここまでは前提です。カテゴリーには関係が重要なのです。例えば私がこうしてイリアスさんに弓矢を放ったなら・・・」
魔道士イリアス「えっ!?あっ、ちょっ・・・きゃあっ!」
騎士サーラ「私がイリアスさんに弓矢を放ったという関係が成立します。矢印のようなものと考えれば簡単ですね。これをといいます」
魔道士イリアス「だからって本当にやらなくても・・・」
騎士サーラ「また、影響を与えた側をドメイン、受けた側をコドメインといいます」
魔道士イリアス「それで、攻撃された私の立場はどうなるのよ!」
騎士サーラ「双対(そうつい)においては、矢印が逆転します。すなわち、影響を受ける側と与える側の関係が逆転し、私がイリアスさんに弓を放ったのではなく、イリアスさんが私に弓を放たれたことになります」
魔道士イリアス「立場って、そういう意味じゃなくて・・・。あれ?この弓矢ってアマンダの・・・」
弓兵アマンダ「げっ・・・」
魔道士イリアス「さてはあなたの差し金ね!C++/CLI魔法・スターダストアロー!」

 「射」を簡単に説明すればこれだけです。単に「a -> b」の関係を少々気取って表現してみただけのものですから、さほど理解は難しくありません。「a -> b」という原則が守られてさえいれば、aとbの関係は何でも構わず、「aはbを友人と考えている」でも「aはbを持っている」でも「aがb言語を習得した」でも構いません。しかし、射はあくまで「a -> b」なのですから、「bはaを友人とは考えていない」かもしれません。

騎士サーラ「ところで、スターダストアローとは何なのでしょう」
魔道士イリアス「*pがあって、p->...とやれば、スターとアローね」
騎士サーラ「ではダストとは何でしょう」
魔道士イリアス「int^とかobject^とか書けば、ダストはGCしてくれるわね」
騎士サーラ「ああ、そうですか・・・。さて、ここでもう1つ重要なことがあります」
魔道士イリアス「今度は何よ?」
騎士サーラ「私がイリアスさんに矢を放ち、イリアスさんがアマンダさんに矢を放ったとすれば、両方とも射の関係になります。それでは、私とアマンダさんにはどのような関係があるのでしょう」
魔道士イリアス「関係も何も、自分の友達の友達は大統領の知り合いだとか、テロリストだとか言うのと変わらないんじゃないの?」
騎士サーラ「射においては、これを射の合成として表すことができます」
魔道士イリアス「なにそれ・・・。意味不明なんだけど・・・」
騎士サーラ「そう難しく考えないでください。イリアスさん、3乗はご存知ですね?」
魔道士イリアス「いくら私でもそれくらい知ってるわよ」
騎士サーラ「では、2^3を暗算で計算するにはどのようなプロセスになりますか?」
魔道士イリアス「そりゃ、まず2*2を計算して、答えの4に2を掛けて・・・」
騎士サーラ「やっていることはそれと同じです。数字に対して2を掛けて、さらに2を掛けるという2つの射を持つのが3乗とするなら、3乗とはこの2つの射を合成したものといえます」
魔道士イリアス「1+2+3とか、5*4*6とかでも成り立ちそうね」
騎士サーラ「はい。そして、実はこの概念こそがモナドに通じるのです」
魔道士イリアス「どういうこと?」
騎士サーラ「射の合成にもいくつか種類があるのですが・・・Haskellにおけるモナドを考えるなら、モナドは合成に用いるものとみて問題はないでしょう」
魔道士イリアス「なるほどねえ・・・」
騎士サーラ「ただし、モナドには制限があります」
・条件1
合成を >>= という記号で表すなら、
(a >>= b) >>= c
a >>= (b >>= c)
この2つは等しくなければならない
魔道士イリアス「じゃ、10-4-5とかは等しくならないわね」
騎士サーラ「はい。それから、これはHaskellでは特に意識されませんが、恒等射というものも必要です」
魔道士イリアス「何それ?聞いたことないけど」
・条件2
a を渡すと a を返す関数 f が存在しなくてはならない
f(a) == a
騎士サーラ「関数型言語においては、例えば10を評価すれば10を返すように、自分を評価すれば自分を返すものが多いですから、自動的に恒等射は存在することになります」
魔道士イリアス「良く分からないけど、変な条件もあったものね」
騎士サーラ「圏論とモナドの基本はこれだけです。簡単ですね」

 以上、圏論とモナドの基礎知識でした。
 しかし、これで抽象的な射とモナド(AとBはどのような関係にあるか)はご理解いただけたことでしょうが、これが現実の計算にどのように結びつくかはまだ不明瞭です。そこで、以下にこの知識をどのように計算に結びつけるかを書いておきます。
 次の例を考えてみましょう。
a -> b -> c
 これの意味は簡単でしょう。しかし、aだのbだのと書いていても具体的な計算に移れませんので、整数を与えてみます。
1 -> 2 -> 3
 とりあえず整数にしてはみましたが、「->」とは一体何なのでしょう。射は何でも構わないのですから、ここでは足し算にしてみましょう。
1 + 2 + 3
 これで一目瞭然でしょう。モナドとは要するにこれだけのことです。「射の合成」を考えれば、
f = 1 -> 2 -> 3
 このような関数が必要になりますが、このfの実体は
f = 1 + 2 + 3
 これなのですから、合成した結果も明らかです。

 それからもう1つ。モナドには「モノイド」と呼ばれるものが存在します。ちなみに、HaskellのMonoidはリスト構造ですが、MonadPlusというクラスで同じ概念が実装されていますので、HaskellにおいてはMonadPlusであるものと考えてください。
 それでは、モノイドとは何か。まずモノイドには二項演算子(「1 + 2」や「5 * 6」のように2つの項目を取る演算子)が定義されていなくてはなりません。その上で、
-> を二項演算子として

・条件1
(a -> b) -> c
a -> (b -> c)
この両者が等しい

・条件2
演算しても結果が変わらない任意の値 mzero が必要
a -> mzero = a
mzero -> a = a
mzero -> mzero = mzero
 この条件を満たさなければなりません。条件1はモナドと同じとして、ここで問題となるのが条件2です。mzeroの値は演算によって異なる値を取りますので、単純にどのような値かを決めることはできません。ちなみに、mzeroのことを単位元と呼びます。
 例えば足し算の場合を考えてみましょう。足し算は任意の数字に0を足せば任意の数字がそのまま返ります。
16 + 0 = 16
0 + 16 = 16
0 + 0 = 0
 したがって、足し算はモノイドの条件を満たすもので、mzeroは0であることが分かります。
 では掛け算はどうでしょう。掛け算においては、1を掛ければ任意の数が返ってきますから、mzeroは1であることが分かります。
32 * 1 = 32
1 * 32 = 32
1 * 1 = 1
 mzeroがゼロではないことに注意が必要です。もしmzeroにゼロを入れて計算してみると、モノイド則を守れないことが分かります。
 また、圏論におけるカテゴリーは何でも取れる非常に抽象的な存在ですから、何も整数だけを演算対象とする必要はありません。マトリックスの乗算を考えてみましょう。
a , mzero はいずれもマトリックス
-> はマトリックスの乗算
a -> mzero = a
mzero -> a = a
mzero -> mzero = mzero
 この場合のmzeroには一体何が入るのでしょう。もしマトリックスが3次元なら
1	0	0
0	1	0
0	0	1
 これです。いかなるマトリックスに対しても、これを乗算すれば同じ値が返りますから、マトリックスの乗算はモノイドであり、mzeroは上記のマトリックスであることが分かります。
 ベクトルも考えてみましょう。ベクトルの足し算の場合は零ベクトルがmzeroであることは容易に想像できます。
(1 , 2 , 3) + (0 , 0 , 0) = (1 , 2 , 3)
(0 , 0 , 0) + (0 , 0 , 0) = (0 , 0 , 0)
 したがって、ベクトルの足し算はモノイドであり、零ベクトルがmzeroであることが分かります。
 これがモノイドの基本的性質です。HaskellにおいてはMonadPlusでモノイドを使用し、mplusが任意の二項演算、mzeroがそのままmzero(単位元)を表します。1度実際に試してみれば、より理解も深まることでしょう。
 さて、ここからはHaskellのモナドを使用する場合には余談ですが、特定の性質を持つ演算にはモノイド以外にも様々な種類があります。Wikipediaのen:Monoidには極めて分かりやすい表(Group-like structures)が記載されているため、興味のある方にはそちらをご覧いただくとして、足し算や掛け算、マトリックス乗算などは「群」(Group)と呼ばれる性質に分類されることが分かります。群はモノイドより結びつきが強いもので、モノイドの性質をいずれも満たした上、逆元がなくてはなりません。
 逆元とは要するに逆算に用いるもので、圏論的に言えば「双対」とでもなるでしょうか。
a -> b = mzero
 まず足し算の場合を考えてみましょう。
a が 5 なら
5 + -5 = 0
 法則を満たすことが分かります。法則といえば難しく聞こえますが、小学校の算数で「5 + x = 11」を「11 - 5 = 6」と習ったのと同じことです。この計算の場合、「6 + 5 = 11」という射を逆転させる演算を検討し、単に「11 + -5 = 6」あるいは「11 - 5 = 6」としただけのことです。
 次に掛け算です。掛け算の逆元は大変有名ですが、一応書いておきましょう。
a が 4 なら
4 * 1/4 = 4 * 0.25 = mzero
 これも単なる逆算に過ぎません。「4 * x = 20」を「20 / 4 = 5」、または分数で「20 * (1/4) = 5」、あるいは小数点を使って「20 * (1 / 4) = 20 * 0.25 = 5」とできるのと全く同じです。
 マトリックスの乗算も考えてみましょう。逆行列を作るのはなかなか難しいのですが、全く数学の知識や習得経験を持たない私でも、この通り作れてしまいました。この逆行列を任意の行列に対して乗算すれば、例えば3次元なら
1	0	0
0	1	0
0	0	1
 このような単位元が得られることが分かります。したがって、マトリックスの乗算にも逆元があります。これもやはり逆算と同じで、「A x B = C」というマトリックスがあるなら、「C x iB = A」(ただしiBはBの逆行列)が得られます。
 ついでですから、英語版Wikipediaの表について少々。

・Closure
 これは資料不足で良く分かりませんでしたが、Haskell風に書いて「a -> a -> a」ということでしょうか。もしこの考え方が当たっているなら、例えば整数というカテゴリーがあるとして、「1 + 2 = 3」の+演算子は整数を取って整数を返す演算ですから、Closureの条件を満たす、と考えることができます。一方、「2 * Vector(3 , 4 , 5)」(数とベクトルの演算)や「Vector(1 , 2) . Vector(3 , 4)」(ドット積。二項はどちらもベクトルだが、ベクトルではなく数を返す)などはこれに当たりません。

・Associativity
 「(a -> b) -> c」と「a -> (b -> c)」を同じとする法則です。足し算や掛け算がこれに当てはまります。

・Identity element
 単位元です。演算に対してmzeroが存在することを表します。なお、「a -> mzero = a」のみを満たすものを「右単位元」、「mzero -> a = a」のみを満たすものを「左単位元」、両方を満たすものを英語で「two-sided identity」または単に「identity」と呼び、日本語ではこれを「単位元」と呼ぶようです。足し算は「10 + 0 = 0 + 10 = 10」で単位元ですが、引き算は「10 - 0 = 10」ではあるものの、「0 - 10 = -10」であって0にならないため、右単位元ではあっても単位元ではありません。

・Inverse
 逆元の存在を表します。要するに逆算ができるかどうかです。

 以上が圏論の基本的な性質です。さほど難しくないことが分かります。
カテゴリ [開発魔法][社会問題][経済・知的財産] [トラックバック 0][コメント 0]

ギョーザ及びその周囲の恐怖
2008/02/04(Mon)02:27:01
 以前に「生ゴミギョーザ」なる問題がありましたが、今度は農薬ギョーザが発見されました。中国製か否かを問わず、危ない食品というものはたびたび問題になりますが、今回ばかりは「単なる食中毒」では済まされません。期限切れのものが少々入っていたり、せいぜい消化不良を起こすといったレベルではなく、食べて死に掛けた人も存在するのです。
 混入ルートは諸説あるようですが、未だにはっきりとしたことは分かっていません。一部のパッケージには穴が開いており、何者かがここから毒物を混入した可能性も指摘されていますが、パッケージに穴が開くことは必ずしも珍しくありません。そもそも人為的なものであるとするなら、誰が何の目的でどのようにそれを行ったのかが分かりません。何らかの事故の可能性も高いのですが、それにしても不明な点が多いようです。
 混入の経緯については調査を待たなければなりませんが、ここで注意すべきことを1つ述べておきましょう。中国産の食品がたびたび問題になっているのは事実ですが、日常生活から中国製品を根絶することはほぼ不可能です。特に加工食品の材料は中国産が少なくないと考えるべきですし、材料は日本産でも中国で加工・生産しているかもしれません。産地に注意するのは悪いことではありませんが、「日本から中国製食品を根絶せよ」と声高に主張する行為には本質的に意味がありません。食料自給率からしても、日本のメーカーの中国依存度からしても、物理的に無理なのです。
 つまり、中国産を完全に排除することはまず不可能なのですが、それなら一体何に注意すべきなのでしょうか。答えは簡単、「中国製品の問題に乗じてひと儲けしてやろう」ともくろむ、国内の浅ましい連中に注意すべきなのです。無論、これは日本国内で良質のものを作ろうと努力している第一次産業の方々のことではありません。中国産の危機をことさら強調して無用な社会不安をあおる連中のことです。
 確かに中国産のリスクは国産より高いとみられます。しかし、「中国産を買うな」などとことさら騒ぎ立ててみたところで意味はありません。そもそも国内でも様々な偽装が存在していることを考えれば、「日本産は買うな」という声が出ても何ら不思議ではありませんが、そのような声を見かけることはありません。今回の問題では命に危険が生じた人も出ており、その点では重大な問題ではあるのですが、国内でも同等以上に重大な問題は発生しています。雪印食中毒やO-157問題を忘れてはいけません。
 念のために明記しておきますが、私は中国を弁護しているわけではありません。もしこのギョーザ問題が中国側の責任によるものであれば、オリンピックなどに現を抜かしている場合ではありません。しかし、人々の危機感を無用にあおって利益を得ようなどという行為は社会不安の原因にもなり、到底容認できません。例えば、「ゲーム脳」などという多くの学者から否定されているインチキ学説を危機感をあおって売り込む評論家、「学力低下」の危機感を必要以上にあおって少子化時代のシェア占有を狙う塾産業、少年犯罪が数十年前から激減している事実を伏せて「少年犯罪・キレる子どもたち」と大々的に恐怖をあおる書籍など、例を出せばきりがありません。
 さらに言えば、日本国内を含めてどこで作られた製品であっても、100%事故や偽装を起こさないことはあり得ません。そして、事故や偽装を完全に防止することができない以上、取引量が多い国の製品に対して「これは危険」と言っていれば、確率論的に見てもじきに必ず的中するのであり、「中国産が危険」なのはある意味当たり前です。
 危険な食品から身を守ることも大事ですが、危険な情報から身を守ることも同様に大事です。中国産に不安を抱かざるを得ないのは事実ですが、このような時こそ立ち止まって冷静に考えてみるべきでしょう。

 一般にも大きく報じられましたが、MicrosoftがYahooに買収提案。これ自体はさほど驚くべきことではありません。MSはGoogleに対抗しうるだけの検索技術をかなり欲しているはずであり、そのためにYahooを買収しようと考えたとしても予想の範囲内です。ちなみに日本のYahooは米Yahooよりもソフトバンクの影響が強いため、米Yahooが買収されても大きな変化はないと考えられています。
 米国のソフトウェア業界自体、ここ数年が転換期となっている印象は否めません。事実上Yahooが占有していた検索シェアをGoogleが切り崩して占有し、MacromediaはAdobeに買収され、GoogleがYouTubeを買い取り、SunがMySQL ABを買収することになりました。いずれも性質が違うこれらの全事象をまとめて扱うのには無理がありますが、いずれもここ最近の大きな動きです。
 ちなみに、YouTubeや今回のYahooとMSの問題こそ日本で報じられましたが、その他の様々な買収問題が日本で大々的に取り上げられることはまれです。したがって、これら以外の買収問題を知らない方も多いはずですので、以下に簡単な概要を述べておきます。
 まずAdobeはPhotoShopやAcrobatで有名な企業であり、日本の官公庁は無駄にAcrobat文章を使用する癖があるなど、同社のソフトウェアは多くの場所で使われています。買収されたMacromediaはShockWaveで有名ですが、Web開発ツールなども手がけています。デザインソフトウェアなどではAdobeの分野と重なる部分も多く、それが買収の動機の1つでしょう。なお、ShockWave及びFlashはメジャーなWebプレイヤー技術であり、Javaアプレットのライバル関係となる存在でしたが、ほどなくJavaはサーバー分野に進出し、この両者が明確なライバルと見なされることは少なくなりました。
 現状において、Javaの開発元であるSunが率いるJava陣営とライバル関係にあるのが、MS率いる.NETです。そして、ここからが少々複雑なのですが、Sunに買収されるというMySQL ABは「データベース」と呼ばれるソフトウェアの開発会社であり、この会社が作成した「MySQL」は世界で最も多く使われているデータベースソフトウェアとされています。YahooやGoogleなどの有力企業もこれを使っているようです。
 さらに複雑なことに、商用データベース分野で最も有名な会社はおそらくOracleですが、このOracleはJava陣営に所属しています。Oracleは先にInnoBase社を買収していますが、これはMySQLで多く使われている「InnoDB」と呼ばれるストレージエンジン(いわばデータベースソフトウェアのパーツ)の開発元で、MySQL ABはInnoBaseとの契約によって期限付きでInnoDBを使用する権利を得ています。データベース分野でMySQL ABとOracleはライバル関係にあるため、Oracleが期限更新を拒む可能性を考えて、MySQL ABは独自のストレージエンジン開発に乗り出していました。そのMySQL ABをSunが買収するわけですから、かなり込み入った状況であることが分かります。
 Googleについても取り上げておくと、Googleは以前にとあるインタビュー記事で「MSとは争うが、Oracleと争う気はない」との方針を述べています。実際、MSは今でも検索分野に力を入れようとしており、さらにYahoo買収提案で検索分野への大々的な進攻を企てているのを見ての通りですが、GoogleとMSが正面衝突する可能性は非常に高い状況です。
 さらに付け足しておくなら、SunはOSである「Solaris」の開発社でもあり、OS分野でもMSとは一応のライバル関係です。また、最近はオープンソース(プログラムのコードが公開されたプログラム)と呼ばれる動きが活発ですが、MySQLはそもそもオープンソースであり、Javaもオープンソース化が進んでいます。Unixと呼ばれるOSの多くもオープンソースなのですが、Mac OSも最近はUnix系オープンソースOSからの派生のようです。そのMac OSの開発元であるAppleは、今まで延々と独自のCPUを発注・開発していましたが、このほどIntelのCPUへの転向を表明しています。
 MSは検索エンジンであるMSNの他、「SoapBox」なる動画投稿サイトも開始していますが、これは明らかにYouTubeの成功を受けたものであり、前述の通りYouTubeはGoogleに買収されています。このような様々な事情からして、MSが手を打っておこうと考えるのは無理もない話です。
 Yahooを買収しようとする最も直接的な理由が「Googleに対抗するため」であることは否定できませんが、上記のような様々な事情も影響していると考えるのが最も自然でしょう。

 せっかくGoogleを取り上げたのですから、ここでもう1つ。皆様、「谷歌」をご存知でしょうか。日本の漢字表記で正確に書くなら「穀歌」となるようです。字面から連想する限り、どこかの山奥の民族に受け継がれてきた伝統か何かでしょうか。「穀物の実りや収穫を祝う伝統的な歌と踊り」のイメージです。
 ところが、実はこの「谷歌」または「穀歌」、Googleの中国名なのです。先進的なイメージが完全に崩壊しており、実際にインターネット上では反対運動まで起こったそうです。Googleは検索の他、様々な技術によるソフトウェアやWebアプリケーションを提供していますが、「谷歌」や「穀歌」からそれを連想することは不可能です。
 さて、なぜここでそのようなことを取り上げるのかといいますと、朝日・読売・日経が共同で提供するサイトの名前が「新's」(あらたにす)であると分かった時に、上記の「谷歌」を連想してしまったためです。はっきり言って「あらたにす」なる名前に「新た」なイメージは全く感じませんし、ひらがなで表記されたものを読むと見間違えそうです。どうせ同じように「ダサい」のなら、いっそ「谷歌」などの方が分かりやすいだけマシというものです。
 しかし、たかだか社説を読み比べできるサイトなどに、現代のインターネット利用者が価値を見出すとは到底考えられません。「MSがYahooを買収」などと大騒ぎされているのに比べ、日本の提携や合併は何と「みみっちい」のでしょうか。

 MSは「.NET戦略」を称しており、C#やVBなどの開発言語を提供しています。開発ツール一式が完全無償のJavaに散々苦戦させられたためか、今ではMSも開発ツールを無償で提供しているのですが、導入するためにはWindows XPのSP 2以上が必要です。ところが、このPCでだいぶ前にSP 2を導入したところ、完全再起不能に陥りました。はっきり言ってあれはウイルスです。
 つまり、このままでは.NETは使えません。しかし、C#言語の存在はかなり魅力的です。何としても開発環境を整備したいものです。ちなみに、新しい技術や言語にも存続するものと滅びるものが存在しますが、この両者の違いは何でしょうか。その時のパラダイムや時の運なども大きな要素ですが、それ以外に1つ重要な差が存在します。
 「企業の要求する機能がそろっているか」などという意見が出てきそうですが、全く違います。最終的にはその言語や技術が面白いか否かです。この点を勘違いしてはいけません。いくら必要な機能を山ほど積み込んでも、面倒であったり面白くないものは邪険にされます。例えば3.0以前のEJBはその代表的な存在です。技術や言語はまず面白く魅力的でなくてはなりません。面白く魅力ある技術や言語には開発者が集まり、自然にコミュニティも大きくなります。仮にその言語が重要な汎用的処理APIを提供していなかったとしても、誰かが必ず標準となるものを作ってくれます。つまり、一言で言い表すなら、面白くない言語に存在する意味はないのです。企業の都合だか何だかで面白くもない言語を作ったところで、経団連におもねるのと何ら変わりません。開発者には相手にされないことでしょう。
 ともかく、.NET戦略だの何だのはどうでも構いませんが、C#は面白そうです。何としても習得したいものです。そこで何とか入手したのが「Mono」でした。これはNovell開発の無償で利用できる.NETコンパイラ及びランタイムであり、C# 3.0の多くの機能に対応しています。言語が英語であり、MS純正品ほど統合した環境を提供していないというデメリットこそありますが、C#を覚える分には何ら問題はありません。
 ちなみに導入方法は極めて簡単で、Monoのサイトからインストーラをダウンロードして実行するだけです。英語など読む必要もありません。インストール終了後には、スタートメニューの「Mono-(Version) for Windows」フォルダ内に「Mono-(Version) Command Prompt」ショートカットが登録されますので、これを実行します。
 これの実体はバッチファイルで、環境変数PATHにmonoのbinディレクトリを設定する効果を持っています。つまり、binディレクトリにあるバッチファイルなりexeなりの名前を指定するだけで、そのプログラムを実行できるようになります。
 それではコマンドをいくつか。
最新版 C# のコンパイル
smcs filename

旧バージョンのコンパイル
gmcs filename
mcs filename

Visual Basic のコンパイル
vbnc filename

旧バージョンのコンパイル
mbas filename

JScript のコンパイル
mjs filename

DLL の登録(標準以外のライブラリを使う際に必要)
gacutil -i dll_file

exe ファイルの実行(CLR)
mono exe_file
 コマンドプロンプトで作業できる辺りがJavaライクで面白いです。せっかくですからMonoに.NETコンパイル用Antも同梱してはもらえないでしょうか。
 さて、首尾よくC#を導入できたら、今度はC#の言語仕様を学ばなければならないのですが、これが実にすさまじく簡単です。C#に限らず、JavaといいPHPといい簡単なのですから。現代のプログラマは幸せです。
 それでもC#やJavaのどこが簡単なのか分からないとおっしゃる皆様、以下の黒魔術を習得するのとどちらがマシでしょうか。
void parse(int data[][2][2] , int max){
	for(int i = 0; i < max; i++){
		int (*d)[2] = data[i];
		int value = d[0][0];
		for(int d3 = 0; d3 < 2; d3++){
			for(int d2 = 0; d2 < 2; d2++){
				d[d2][d3] = value;
				value *= 2;
			}
		}
	}
}

void main(){
	int data[][2][2] = {
		{
			{1 , 0} ,
			{0 , 0}
		} , {
			{4 , 0} ,
			{0 , 0}
		} , {
			{16 , 0} ,
			{0 , 0}
		}
	};

	parse(data , 3);

	int *p = (int*)data;
	int sum = 0;
	for(int i = 0; i < 12; i++){
		sum += p[i];
	}

	printf("%d" , sum);	// 315
}
 ざっとポインタ及び配列の用例を示しただけですが、これだけで少々意味不明になっています。その点、C#やJavaは非常に恵まれた言語なのです。
 C#言語は当初「Javaの模倣」と言われただけはあり、非常にJavaに似ています。つまり、Javaさえ覚えていればC#も簡単に習得できます。さらに、C++から持ってきたらしい構文が非常に多いのも特徴です。
// クラスの継承記述及び親コンストラクタ呼び出し
// C++
class Child : public Parent{
public:
	Child(int);
};
Child::Child(int i) : Parent(i){
}

// Java
public class Child extends Parent{
	public Child(int i){
		super(i);
	}
}

// C#
public class Child : Parent{
	public Child(int i) : Parent(i){
	}
}
 ということで、C++を覚えていると非常に通りが良いのです。苦労して習得しておいて助かりました。C#では多重継承は禁じられていますが、「class Class : ClassA , InterfaceB」といった具合にC++の構文で継承クラスとインタフェースを並べることができます。クラスとインタフェースの両方を継承する場合には、クラスを1番前に置くようです。多重継承ができませんので、virtual継承はなくなっています。また、C++ではあまり必要とされていなかったためか、private及びprotected継承の構文はないようです。
 メソッドには仮想メソッドが存在し、C++同様に仮想メソッド(仮想関数)でないメソッドを親クラス型から呼び出すことはできません。さらに、仮想メソッドを継承する際にはoverride、継承しない際にはnew宣言を付加し、開発者の意図を明確にしなくてはなりません。
public class Knight{
	// 武器はクラスによって変更したいため、仮想メソッドにする
	public virtual string GetWeapon(){
		return "剣";
	}
	// 分類はクラス型のものを用いるようにする
	public string GetClassified(){
		return "ナイト";
	}
}
public class DualKnight : Knight{
	// 継承するので override 宣言をしなければならない
	public override string GetWeapon(){
		return "大剣";
	}
	// new 宣言で継承しないメソッドであることを明示
	public new string GetClassified(){
		return "デュアルナイト";
	}
}

// 実行コード
Knight knight = new DualKnight();
Console.WriteLine(knight.GetWeapon());	// 大剣
Console.WriteLine(knight.GetClassified());	// ナイト
 また、純粋仮想関数を作ることもできます。この場合、C++のようにvirtualメソッドに0を代入するのではなく、Java同様にabstract宣言でメソッドを定義します。
// Developer クラス
// この時点では抽象的で、どのような言語を使う開発者かは分からない
abstract public class Developer{
	public abstract string GetLanguage();
}
// OOPDeveloper クラス
// OOP なのは分かったが、どのような言語なのかは分からない
abstract public class OOPDeveloper : Developer{
}
// CSharpDeveloper クラス
// C# を使えることが具体化
public class CSharpDeveloper : OOPDeveloper{
	public override string GetLanguage(){
		return "C#";
	}
}
 abstract宣言にはvirtualが内包され、abstractとだけ書けばvirtualとみなされます。abstractメソッドを含むクラスはabstractクラスになります。
 abstractクラスは継承して使うことが前提ですが、たとえこれを継承したとしても、継承先でabstract宣言されたメソッドを実装しない限り、抽象ではないクラス(concrete)にすることはできません。この辺りはJavaやC++と全く変わりません。
 一方、C#では抽象メソッドを実装する場合でもoverride宣言を書かなくてはなりません。オーバーライドすることなど分かりきったことですが、書かなくてはならないものは仕方がありません(ただしインターフェイスでは違います。詳しくは後述)。
 その代わり、C#ではどれが仮想関数か分からなくなる状態は回避できます。C++ではvirtual宣言された関数は子孫でも永久にvirtualされるのですが、次のような場合はそれが明確でなくなることがありました。
class Parent{
public:
	virtual void Function();
};

class Child : public Parent{
public:
	// virtual を書かなくても暗黙のうちに virtual
	void Function();
};

class GrandChild : public Child{
public:
	// したがって、これも仮想関数
	// ...なのだが、Child を見るだけでは分からない
	void Function();
};
 C#ではこのようになります。
public class Parent{
	// 仮想メソッド
	public virtual void Function(){
	}
}

public class Child : Parent{
	// override がついているので、virtual メソッドの継承であると分かる
	public override void Function(){
	}
}

public class GrandChild : Child{
	// これも virtual メソッドの継承であることが分かる
	public override void Function(){
	}
}
 それから、忘れてはならないのがアクセサ機能です。これはプロパティに干渉するメソッドとでも呼ぶべきもので、JavaBeansのget/setに相当します。
// 市民
public class People{
	private string name;
	private string nation;
	// 名前
	public string Name{
		get{
			return name;
		}
		set{
			// value にはセットされた値が入っている
			name = value;
		}
	}
	// 国
	public string Nation{
		get{
			return nation;
		}
		set{
			nation = value;
		}
	}
}

// 呼び出し方
People p1 = new People();
p1.Name = "Ada Smalltalk";
p1.Nation = "USA";

People p2 = new People();
p2.Name = "配 孫";
p2.Nation = "China";

People p3 = new People();
p3.Name = "四都 蘭";
p3.Nation = "Japan";
 このように、アクセサにはプロパティと同様にアクセスできます。その際にはアクセサの記述が呼び出されるため、値の正当性チェックなどを行うことができます。また、get及びsetのどちらか片方を書かないことも可能であり、getだけ書けば読み取り専用、setだけなら書き込み専用のアクセサとなります。
 さらに、アクセサはオーバーライドしたり、抽象化したりすることが可能です。先ほどの「市民」クラスを継承して開発者を作ってみましょう。
// 言語のリストを取得するインターフェイス
public interface DevelopmentSkill{
	// 抽象アクセサ
	List<string> Languages{
		get;
	}
}
// 開発者
public class Developer : People , DevelopmentSkill{
	private List<string> languages;
	public List<string> Languages{
		get{
			return languages;
		}
		// インターフェイスで義務付けられているのは get のみだが
		// 任意で set を実装しても構わない
		set{
			languages = value;
		}
	}

	public Developer(){
		languages = new List<string>();
		languages.Add("C++");
		languages.Add("C#");
		languages.Add("Perl");
	}
}

// 使い方
Developer d = new Developer();
List<string> langs = d.Languages;

foreach(string lang in langs)
	Console.WriteLine(lang);
 なお、基底クラスと派生クラスで同じ名前のアクセサを作る場合、メソッド同様にvirtualとoverride宣言が必要です。オーバーライドしないこともできますが、その場合はnew宣言が必要です。
 上記ソースではついでにインターフェイスも使用してみましたが、Javaのインタフェース及びC#のabstractのみのクラスとは次の点で違いがあります。

・Javaではインタフェースのメンバにpublicやabstractをつけることができたが(自動的にabstractかつpublicになるため、宣言しても意味はない)、C#ではしっかりエラーを出してくる
・インターフェイスを継承したクラスでは、継承したメソッドやアクセサなどにoverride宣言が必要ではなく、つけるとエラーが出る
・メソッドとアクセサの他、イベントとインデクサの宣言も含むことができる(インデクサとはoperator []のようなもの。イベントは関数ポインタのようなものであるが、「イベントの宣言」とは関数ポインタの引数型と返り値をtypedefするようなもの)
・Javaと違い、定数を宣言することはできない
・複数のインターフェイスから同じ名前のメソッドその他をそれぞれ継承することができる

 まずイベント宣言について軽く解説しておきましょう。C++に例えるなら、イベント宣言とはこのようなものです。
// 関数ポインタ型(イベント)を宣言するクラス
// ここでは int(int,int) の関数ポインタに Type という名前をつけている
template<class T> class FuncPointer{
public:
	typedef int(T::*Type)(int,int);
};

// 何でも良いので適当なクラス
class Calc{
public:
	// int(int,int) の関数
	int plus(int a , int b){
		return a + b;
	}
};

void main(){
	// 後は簡単に使用できる
	FuncPointer<Calc>::Type fp = &Calc::plus;
	Calc c;
	Calc *p = &c;
	printf("%d" , (p->*fp)(10 , 20));
}
 これが上記より簡単に行えます。
 もう1つ、同名のメソッドを複数継承する方法も記述しておきましょう。例えば次のようなクラスを考えてください。
// 好きな食物を取得するインターフェイス
public interface Foods{
	string GetLike();
}

// I(私) クラス
public class I : Foods{
	string GetLike(){
		return "コーヒー";
	}
}
 これは見たままでしょう。Iのインスタンスに対してGetLike()を呼び出すのは、「あなたの好きな食べ物は何ですか?」と聞くのと同じです。
 しかし、人間たるもの、好きなものなど色々あるのが普通です。
public interface Foods{
	string GetLike();
}
public interface ProgramLanguages{
	string GetLike();
}
public interface MusicGenres{
	string GetLike();
}

public class I : Foods , ProgramLanguage , MusicGenres{
	public string GetLike(){
		// ...
	}
}
 さあ、私は一体何と答えれば良いのでしょうか。「好きな食べ物は?」「好きな言語は?」「好きな音楽の種類は?」の3つの質問に対して、1つの答えしか返せないのです。これでは何とも答えようがありません。
 そこで、各インターフェイスのメソッドをそれぞれ継承する方法を用います。
public interface Foods{
	string GetLike();
}
public interface ProgramLanguages{
	string GetLike();
}
public interface MusicGenres{
	string GetLike();
}

public class I : Foods , ProgramLanguages , MusicGenres{
	string Foods.GetLike(){
		return "コーヒー";
	}
	string ProgramLanguages.GetLike(){
		return "C#";
	}
	string MusicGenres.GetLike(){
		return "フォーク";
	}
}

// 使い方
// それぞれキャストなしに呼び出すことはできない
I person = new I();
Console.WriteLine(((Foods)person).GetLike());
Console.WriteLine(((ProgramLanguages)person).GetLike());
Console.WriteLine(((MusicGenres)person).GetLike());
 その他、sealedなる宣言も存在します。これはJavaのクラスやメソッドに対するfinalと同じもので、クラスをsealedすると継承できなくなりますし、メソッドをsealedするとオーバーライドできなくなります。ちなみに、C#ではvirtualされていないメソッドはそもそもオーバーライドできず、継承を許可するvirtualと継承を阻止するsealedを同じメソッドにつける行為には全く意味がありません。new宣言されているメソッドはオーバーライドではないことを明示しているわけですから、こちらもsealedする意味はありません。つまり、sealedをつけられるメソッドはoverrideメソッドのみということになりますが、その際にはoverrideの前にsealedと書く(public sealed override type Method())ようです。
 これでC#のクラス周りの仕様はおおむね全部でしょうか。C++に比べればかわいいものです。
カテゴリ [開発魔法][社会問題][経済・知的財産] [トラックバック 0][コメント 0]

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