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

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
ゼロ相続税政策
2009/02/10(Tue)00:07:19
 金配りに始まって、派遣村の人々を(機動隊とも衝突した暴動である)学生運動呼ばわりしたり、渡りあっせんを認めると言ったり禁止と言ったり、国会を迂回して金配りをしようとしてみたり、郵政民営化に反対と言った後で賛成してみたりと、このところ麻生氏及び内閣・自民党の面々には意味不明な行動が目立ちます。サブプライムからの一連の不況の波をかぶっていながら内輪モメとは、どうやら麻生内閣には相当の余裕があるようです。
 ところが、これらだけでも憂慮すべき事態であるにもかかわらず、このほどさらにとんでもない案が登場しました。無利子である代わりに相続税を免除する国債を作ろうという案が自民党内に持ち上がってきたのです。最近は「政府紙幣」などいくつかの奇策が論じられているようですが、これもその1つであるといえそうです。
 経営学上、現在の資産は未来の同額の資産よりも価値が高いとみなされるため、この案の理念は分からないわけではありません。無利子で手に入れた金を運用にまわせば収益が期待できますし、これで有利子負債を圧縮すれば利払いが回避できます。国としては、相続税を得ない代わりに運用益や有利子負債の削減で利益を得られれば良いわけですし、利子を気にする必要のない借金ができるのは確かに魅力でしょう。十分な運用益の確保なり負債の圧縮なりが可能になれば、相続税を得るよりも利益が大きくなるとの考えがあったとしても不思議はありません。
 しかしながら、私は現段階ではこの制度に強く反対します。この案はあくまで「案」の段階に過ぎませんので、相続税は全額免除か一部免除か、国債にはどのような制限をつけるのかなど、まだはっきりとしたことは分かりませんが、いずれにしても得策とは考えられません。
 この問題に入る前に、まずは相続税法について簡単に解説しておきましょう。相続税とはその名の通り、所有者の死去などによって他者に受け継がれた財産にかかる税で、税率は相続額によって変わります。また、同法15条によって定められている基礎控除の規定によれば、色々と複雑な規定はあるものの、ごく単純には「5000万円 + 相続人の数x1000万円」以内であれば相続税はかかりません。したがって、一般人には相続税がかからないか、かかったとしてもごく一部にしかなりませんので、対象の多くは資産家であるといえます。
 同法16条によると、税率は以下のように定められています。

千万円以下の金額百分の十
千万円を超え三千万円以下の金額百分の十五
三千万円を超え五千万円以下の金額百分の二十
五千万円を超え一億円以下の金額百分の三十
一億円を超え三億円以下の金額百分の四十
三億円を超える金額百分の五十

※2009/02/13追記
 この表だけでは分かりづらいので、上記リンクの「相続税法」をわざわざ読みたくない方のために、計算方法を補足しておきます。
 まず相続額から控除額を減算します。計算式は上記の通り、単純には「5000万円 + 相続人の数x1000万円」です。こうして得られた相続税対象額のうち、まず1000万円までの部分に10%の税をかけ、それ以上で3000万円までの部分には15%の税をかけます。これを繰り返し、全部合計した額が課税額となります。
 仮に相続額10億、控除6000万円であるなら、9億4000万円は3億円を超えていますので、3億円以下の部分をすべて適用し、まず1億300万円が課税されます。さらに、3億円以上の部分が6億4000万円ありますので、こちらには3億2000万円が課税されます。したがって、最終的には4億2300万円(約42%)の課税です。同じく控除額を6000万円として、相続額が20億円なら9億2300万円(約46%)、1億円なら600万円(約6%)と、税率は金額に強く比例します。

 つまり、相続税は累進性の高い税であるといえます。
 無利子国債の話に戻りましょう。今回問題の無利子国債とは、すなわち上記の税を免除するものです。免除が全部か一部かは不明ですが、前述の通り相続税は一般人にはあまり縁のないものですので、この案は金持ちの選択肢を増やすものでしかあり得ません。対象者は当然、自分にとって最も有利なもの、すなわち相続税の累進性ができるだけ回避され、しかも国に支払う額が最小限となる方法を選ぶでしょう。したがって、この案に賛成できる理由が見つかりません。
 例外として、もし以下のような極端な条件で国債を発行するのであれば、支持しても良いかと考えています。いずれの方法も、生前贈与で相続税を回避したり、国債が市場で売買されたり、経済状況が変化したりといった可能性を考えると、必ずしも思惑通りに進むとは言いがたいのですが、少なくともこの程度の条件はつけなければ、到底容認できるものではありません。

・超長期無利子国債
 無利子国債の相続税を免除する代わりに、例えば30年後に同額が得られる国債を発行する方法です。課税対象額が3億円以上の部分ともなると、単純計算では実にその半分が相続税として徴収されるのですが、多少のことでこれを免除してしまっては、課税逃れに使われるのは確実でしょう。何といっても半額、つまり最大課税対象額が10億なら5億が徴収されるのですから、金持ちがこれを回避したがるのは当たり前です。
 定められた期間内に、手元にある資金を倍にするのに必要な年利(複利計算)は、30年であれば約2.337%、50年なら約1.396%といったところです。仮に最大課税対象額が10億あるとして、そのまま相続すれば半分が消えて5億となります。これを元の額に回復するには、前述の年数と金利が必要なのです。もしそれを普通に相続した後、1.396%以上の年利を出せないのであれば、50年無利子国債の方が得ということになります。
 現在の経済状況では1%の金利すら困難ですが、30年や50年となれば状況も大幅に変わると考えられますし、物価が上がれば国債の価値は相対的に低くなります。経済成長などを加味すれば、数%程度の金利は妥当なところでしょう。もし相続税を免除した上、国債購入額と同等の額面での返還を保証するのであれば、少なくともこの程度の長期国債にはならざるを得ません。国としては、無利子国債で有利子負債を圧縮すれば、その分の利払いの必要がなくなりますので、ここまで長期にしなくても十分に利益を得ることはできるはずですが、国は良くても制度としては不公平です。一般人が1%や2%程度の金利さえ容易には得られない中、金持ちが無利子国債を5年ほど保有して半額の相続税を回避したなら、利息に換算すると実に年利14.87%にもなるのです。これが不公平でないとすれば、何が不公平なのでしょうか。
 ただし、この国債を市場で自由に売買できてしまうと、相続前に買って終わったら売るなどして課税逃れが出ないとも限りませんので、この点の調整は必要です。

・高額打歩国債
 相続税による課税は、最大の課税対象部分では半額にも及びます。したがって、この徴収を逃れるためであれば、打歩(額面よりも売価の方が高い債権)発行の国債でも買う理由が存在します。仮に@160なるとてつもない額(160円払うと100円分の国債が得られる)の国債であっても、通常の相続税の最大課税であれば割合は半額となり、仮に課税対象額が16億なら8億が引かれてしまうのですから、この打歩国債を買って16億を10億にした方がまだ利益が大きいのです。
 実際には、相続税には5000万円以上の控除があり、課税対象額が3億円以上でなければ税の割合は半額より低く、また国債を保有している間は利子がつきませんので、それを考えると必ず得するとはいえないのですが、これほどであってもなお利益を得られるケースも存在するのです。

 上記の案はいずれも現実的なものとはいえず、私もこれらのような案が本気で実現されるなどとは考えていませんが、上記のようなあまりにも極端な案ですら、あくまで理論上の話ではありますが、金持ちに利益をもたらす場合があるのです。政府が検討するような案となればなおさらでしょう。そもそも、自分の利益にならない国債など誰も買うわけがないのですから、金持ちがこのような無利子国債をあえて購入するということは、彼らにとっては相続税上の利点がある、すなわち金持ちを相続税の面で優遇していることを意味します。
 「貧困の連鎖」さえ指摘されるこのご時世にあって、金持ちの相続税を優遇する国債を発行しようとは、一体どのような了見なのでしょうか。相続税以外の金持ち優遇については、例えば所得税の最高税率が引き下げられた事例について、金持ちの一部には「努力や才能の結果なのだから、金持ち優遇の批判は当たらない」と称する者も見られますが、私は当然ながらこのような見解には同意しません。しかし、仮に百歩譲ってその言い分を認めるとしても、相続税となればわけが違います。相続税まで優遇する必要がどこにあるのでしょうか
 確かに、国にとっては都合の良い案なのかもしれません。金持ちは国債によって相続税を回避し、国は無利子で得た借入金を運用したり、あるいは有利子負債の圧縮に使用すれば、双方が通常より多くの利益を得られる可能性があります。しかしながら、これを「ウイン・ウインの関係」などとして容認するのは早計に過ぎます。このような行為は、累進性、富の再配分、格差の固定化防止といった相続税の理念を否定するものであることを忘れてはいけません
 いい加減、政治家の誰かが相続をしたり受けたりするために言い出したのではないかと勘繰りたくもなります。案の内容が全くまとまっていない現段階では、あまり詳細な部分に立ち入って論じることはできませんし、金持ち優遇色が十分に薄められる可能性もゼロとまでは言い切れませんが、少なくとも現段階では本案には賛成しかねます。

 あるタレントのブログに対し、「女子高生コンクリート詰め殺人」の犯人であるなどと虚偽の書き込みをしていた19人が、名誉毀損や脅迫の容疑で検察官送致の運びとなりました。かの事件の痛ましさは今さら説明するまでもありませんが、名誉毀損や脅迫を受けた被害者は本事件とは何の関係もなく、したがって攻撃を受けるいわれは全くありませんでした。
 私はインターネットの問題をむやみに取り締まるのには反対の立場です。例えばWinny作者の逮捕のような問題に関しては、私自身はWinnyのようなソフトを使用した経験はありませんが、許されないと主張してきました。インターネットの規制法に関しても、基本的には反対の立場です。インターネットは基本的に自由であるべきで、規制法などによって下手に権力が介在しようものなら、なし崩し的に権力の介入が認められかねませんので、私は絶対にそれを容認しません。
 しかしながら、私は本件の警察の対応には強く賛同します。根も葉もない嘘によって他人の名誉を傷つけ、さらには脅迫を行った者までいたとなれば、それは単なる卑劣な犯罪行為に過ぎず、自由として守られる価値などありません。インターネットに無用な規制を持ち込んではいけませんが、こうした例は積極的に取り締まるようにすべきです。
 まずはっきりさせておかなくてはならないのは、もし本件の被害者が本当にコンクリート詰め事件の加害者であったとしても、中傷行為を行うのは許されないという点です。本件の被害者は言うまでもなく事件の加害者ではなく、中傷は完全に事実無根です。しかし、仮に事件の加害者に対してであっても、名誉を傷つけるような行為は許されません。
 以下、名誉毀損及び侮辱罪の引用です。

(名誉毀損)
第二百三十条  公然と事実を摘示し、人の名誉を毀損した者は、その事実の有無にかかわらず、三年以下の懲役若しくは禁錮又は五十万円以下の罰金に処する。
2  死者の名誉を毀損した者は、虚偽の事実を摘示することによってした場合でなければ、罰しない。

(公共の利害に関する場合の特例)
第二百三十条の二  前条第一項の行為が公共の利害に関する事実に係り、かつ、その目的が専ら公益を図ることにあったと認める場合には、事実の真否を判断し、真実であることの証明があったときは、これを罰しない。
2  前項の規定の適用については、公訴が提起されるに至っていない人の犯罪行為に関する事実は、公共の利害に関する事実とみなす。
3  前条第一項の行為が公務員又は公選による公務員の候補者に関する事実に係る場合には、事実の真否を判断し、真実であることの証明があったときは、これを罰しない。

(侮辱)
第二百三十一条  事実を摘示しなくても、公然と人を侮辱した者は、拘留又は科料に処する。
(太字は引用者による)

 名誉毀損罪には例外が2つあり、「死者の名誉を真実によって毀損した場合」と「事実の摘示が公共の利益のために行われ、しかも摘示された事実を真実と信じるに足る証拠があった場合」には罰せられません。逆に言えば、存命中の元犯罪者の名誉を「真実によって」毀損した場合であっても罰せられます。仮にコンクリート事件の加害者がブログを書いていたとしても、それを指摘して名誉を毀損すれば名誉毀損に当たります。ちなみに、名誉毀損の例外として「公共の利益にかかる場合」があると述べましたが、いくら相手が元加害者であったとしても、単にブログを書いているだけの相手の名誉を毀損する行為が「公共の利益」とみなされる可能性はほぼ確実にゼロです。すなわち、それは3年以下の懲役に処せられる恐れもある犯罪行為です。
 また、ブログなどを中心に、まれに「炎上」と呼ばれる現象が発生する場合があります。炎上の原因には様々なものがあり、万引きなどの犯罪行為をブログに書いたり、記事で他人を根拠もなく中傷したりといった行為によって炎上する非常識なケースもあれば、ブログの著者が意見の分かれる問題に言及したために、著者の意見に賛同しない人が寄ってたかってブログに書き込みを開始し、炎上してしまうケースもあります。
 「炎上」の書き込みの中にも、著者にしっかり反論または抗議するような比較的まともなものもあれば、単なる誹謗中傷や脅迫でしかないものもありますが、後者はほぼ確実に名誉毀損、侮辱、脅迫、威力業務妨害といった罪にあたります。また前者であっても、数百数千という大量の炎上書き込みが殺到している異常事態の中で、さらに書き込みを増やすわけですから、確実に罪に問われないとは言い切れません。短期間の大量書き込みによる負荷と容量の増大など、サーバー業者に実害を生じさせる可能性も考えられます。
 炎上の中には、明らかに著者に問題があるものも多く存在しますが、それでも誹謗中傷の免罪符とはなりません。著者が記事中で他者の名誉を傷つけ、その記事が炎上を起こしたとして、ここで著者を中傷するようなコメントが書かれていたら、両者ともに名誉毀損や侮辱罪に抵触しています。行動のレベルは全く同じと言い換えても良いでしょう。
 ましてや、議論のある問題について意見を述べたことに対する炎上や、今回のように事実無根の流言に端を発した炎上は、全く正当化のしようがありません。議論のある問題に対する炎上の場合、ブログ著者が多少「トゲのある」表現をして問題提起をしているケースも見受けられますが、このような問題提起の手法はかねてから様々なメディアで用いられており、特別なものではありません。これを行ってはいけないというのであれば、当たり障りのない表現しかできなくなってしまいます。
 既存のマスコミは様々な捏造や隠蔽を行っており、ことに議論のある問題、タブーとされる問題については、ろくに取り上げようとしないか、あるいは自社の主張に沿う情報ばかり取り上げる傾向にありました。インターネットが登場したおかげで、このようなマスコミの捏造・隠蔽報道を介さずに意見を述べたり議論をしたりできるようになったにもかかわらず、議論のある問題を書くと炎上の危険にさらされるようでは、インターネットで自由な意見を述べられなくなります。これは非常に大きな損失でしょう。
 さらに、ある大手サイトに「ブログ炎上」への対策を書いた記事がありましたが、ここでは「炎上させた側に責任がある」と言わんばかりの論調を取っており、「まず謝罪」が対策であるとしていました。確かに、炎上の中には著者に責任があるケースも多く、このような著者が謝罪を書くのは当然です。しかし、著者に責められる点があるからといって、中傷コメントで炎上に加担して良いわけがありません。本人は正義の味方にでもなったつもりなのかもしれませんが、これは単なる犯罪行為に過ぎず、その実KKKが黒人や黄色人種を誘拐してリンチを加えるのと何ら変わるところはありません。これは、今回の事件のように相手が何らかの事件の元加害者と噂されている場合も同じですし、仮にそれが事実であっても同じです。無論、相手にはこれといった非がないのに、意見が気に入らないからといって炎上に加担するような行為は、ただの一方的な言葉の暴力に過ぎません。
 時として、炎上なのか大量のまっとうなコメントなのか、意見なのか名誉毀損なのかが分かりづらいようなケースも存在するとはみられますが、少なくとも明らかに中傷にしか見えないような書き込みは、しっかり取り締まられなくてはなりません。
 違法行為はインターネット内だけにとどまるとは限りません。以前にイラク人質事件が発生した際、家族に大量の中傷電話がかけられたことがありましたが、社会生活を脅かしている分「炎上」より悪質といえます。Webサイトなどで被害者らの行為を「軽率」と批判するのは自由ですし、それが警察によって取り締まられるようなら私はそれを絶対に容認しませんが、電話をかけて中傷するなどといった行為が許されるわけがありません。名誉毀損や侮辱の他、精神的に追い詰めれば傷害罪すら適用される場合があります。ブログ炎上のコメントの中にはまっとうな意見もありますので、これを全部取り締まるのには賛成できませんが、被害者宅にわざわざ電話をかけたとなると、何をもってしても正当化は不可能ですから、このようなケースでは確実に全員が取り締まられなければなりません。こうした中傷をはじめとした、法を守る気も何もない嫌がらせに対しては、必罰による一般予防で当たる以外にありません。
 インターネットつながりで、最近の判決にも触れておきましょう。このほど、虚偽の書き込みに対する裁判の2審判決が出たとの記事がありました。1審では「インターネットの書き込みは信頼性が低いとみなされており、通常の報道ほど厳密な証拠は不要」との判決が出ていましたが、2審ではこれを破棄して「インターネットのみをそのような扱いにするのは不合理」との判決を下しました。これはおおむね妥当な判決でしょう。インターネットについて「便所の落書き」などと称する人も見られますが、司法は「便所の落書きではいけない」と言っているのです。インターネットは現在よりもさらに「信頼性のあるメディア」とみなされるようになるべきであり、「表現の責任」の自覚が必要です。
 例えば、先に取り上げたイラク人質事件ですが、当初に一部では自作自演説もささやかれたそうです。それを誇らしげに書いてあるブログも見つけました。証拠もなしに決め付けるのはいかがなものかという気もしますが、様々な人の視点から物事を眺められるのがブログの長所ですから、ここまでは構いません。むしろ問題は、自作自演説が完全にあり得ないと分かった後に、記事を謝罪の上で撤回したブログを見たことがない点です。被害者に不当な嫌疑を着せた上、閲覧者には結果的に明らかな誤報を伝えてしまったのですから、表現の責任として読者に一言伝える程度はできないのでしょうか。そのような責任を取る気がなければ、最初から表現などしない方が賢明です。
 今回の「コンクリート詰め」炎上事件をめぐっては、複数のマスコミがインターネットを批判するかのような論調の主張をしています。例えば読売新聞は、「「表現の自由」には責任が伴う」という題名の社説を掲げています。これ自体は全くその通りで、私も上記で同じように主張しています。しかしながら、「表現の責任」を最も守っていないのは誰でしょうか。私が考えるに、それは「炎上」への加担者でも、上記に述べたようなブログの執筆者でもなく、新聞社などのマスコミに他なりません。
 マスコミの横暴はここでも散々取り上げてきましたので、もはや説明の必要もないでしょう。朝日新聞をはじめとした捏造報道は有名ですし、河野氏などの冤罪を作り上げたのもマスコミです。何かショッキングな殺人事件でも発生すれば、被害者の家や葬式にすらよってたかって押しかけ、不法侵入やタバコ・空き缶のポイ捨てなどの最悪な行為を行います。それでいて、遺族の手記にマスコミ批判の部分があれば、被害者を失った悲しみなどの部分はそのまま引用しておきながら、批判部分は隠蔽して報道します。読売といえば、尼崎・福知山線脱線事故の時に「社長を出せ」と怒鳴りつけた記者は確か読売でした。プロ野球ストの際には「超高額所得者のスト」なる社説を出していますし、同系列の日本テレビが視聴率調査で不正を働いた後にも、社説に「(テレビ朝日のダイオキシン報道や、他社の誤認報道などを取り上げて)他山の石としたい」と書いた際には「日テレ」の文字は1回も出てきませんでした。
 事例はまだまだ大量にありますが、ここではこれ以上は触れません。しかし、何とも格好がつかないことに、先のような「責任を取らない」ブログと似たような行為をしたマスコミがある点には触れておかなくてはなりません。
 イラクの話ばかりで恐縮ですが、以前に米国が「イラクは大量破壊兵器を45分以内に配備できる」と主張して戦争に踏み切りました。大量破壊兵器があるかさえ怪しいのに、米国はさらに「それを45分以内に配置できる」という立証責任までもを負っており、この時点で現実的にまずあり得ない主張であるのは明白でした。少なくとも私は、この時点であり得ないと確信していました。
 当時の首相である小泉氏は米国への支持を明確にしましたが、新聞社の論調は割れていました。そのうち、「イラク戦争には反対」「日米同盟維持のために賛成」といった意見には問題はありません。しかしながら、中には「イラクは大量破壊兵器を持っている」「兵器がテロリストに渡れば、日本の安全も脅かされる」などといった論調で戦争を正当化するマスコミもありました。急先鋒が産経新聞、その次が読売新聞です。
 今からすれば噴飯ものですが、当時は誰にも真実は分かりませんでした。何の根拠もなく大量破壊兵器があると断定し、その仮定を元に支持の理屈を作ったのは失敗でしたが、いくら報道たるものが慎重でなければならないとはいっても、勇み足は誰にでもあるものです。他ならぬ米国が「ある」と言い張っていたのですから、信じてしまっても無理はありません。
 しかし、問題はその後です。イラクをいくら探してみても、大量破壊兵器など影も形もなかったのです。「なさそう」が主流意見になっても、産経新聞はご丁寧にも米国の研究機関の論文を引用し、社説で「この通り、大量破壊兵器はある」と言い張っていました。しかし、産経新聞の論説委員の方々は英語は読めるようですが、米国の研究機関が「大量破壊兵器は存在する」と主張するのは当たり前であることには誰も気づかなかったようです。
 このように、産経新聞その他の新聞社は、社説でとはいえ明らかに正しくない情報を流し、読者に誤った認識を与えた恐れがあるにもかかわらず、それを謝罪・撤回したという話は聞いたことがありません。一方、ブッシュ氏のイラク戦争を支持した外国紙の中には、「なぜ我々はだまされたのか」などとする検証記事を書いたところもあるといいます。これこそ「表現の責任」を重んじるジャーナリズムというものですが、翻って日本はどうでしょうか。
 「表現の責任」は極めて大事です。事実無根の名誉毀損などを行えば、責任を取らなくてはならないのは当然です。インターネットであれ何であれ、表現の自由には表現の責任が付属しており、自分の表現には責任を持たなくてはなりません。表現に責任を持つことは、表現の信頼性を高める上でも重要です。しかしながら、マスコミには他者の「表現の責任」を指摘し、インターネットを批判する権利はありません。誰が最も表現の責任を踏みにじっているかを自覚し、恥を知るべきでしょう。

 まずは前回の「カット」の続きから。
 カットが一方通行であるのは前に述べました。ところで、カットの有効範囲はどこからどこまでなのでしょうか。ここに述語aがあるとして、仮にこの中から述語bを呼び出し、さらに述語cを呼び出し、述語cにカットがあったとします。述語cに一方通行があるからといって、aやbにも戻らなくなるのは動作として不自然です。そもそも、もしPrologが述語aからb、そしてcまで探索し、cの一方通行によってaにもbにも戻らなくなってしまうのなら、ほとんど行き倒れの旅人です。いくら探索中の不慮の事故とはいえ、これではあまりにも気の毒な処遇です。
 これを確かめるには、実際に試してみるのが最善でしょう。
way(right).
way(left).

a(A , B , C) :- way(A) , b(B , C).
b(B , C) :- way(B) , c(C).
c(C) :- way(C) , !.
 まず述語aに入り、左右に分かれた道のいずれかを通って述語bに行き着きます。bはさらに同様にしてcに行き着きます。cでも道は二手に分かれており、どちらに進んでも一方通行になっています。これを実行すると、いかなる結果が得られるのでしょうか。
?- a(A , B , C).
A = right,
B = right,
C = right ;
A = right,
B = left,
C = right ;
A = left,
B = right,
C = right ;
A = left,
B = left,
C = right.
 述語a及びbの道は左右両方を探索している一方、cでは右の道しか探索していないようです。これは、cの分岐点でまず右に進むと一方通行になっており、バックトラックして左の分岐には進めないためです。一方でaとbは何事もなく探索されていますので、カットの有効範囲は「述語毎」、さらに正しく表現すれば「呼び出し毎」であると考えられます。
 迷路に例えるなら、まず探検家Prologはaと呼ばれる洞窟を探検します。洞窟に入ると、道がrightとleftに分かれています。ひとまず右に進むと、今度は洞窟bの入り口に行き着きました。ここも道が二手に分かれており、こちらもひとまず右に進みました。すると、さらに洞窟cの入り口に行き着きました。これも道が分かれており、右に進むと一方通行でした。これによって先ほどの分岐点に戻って探索する必要のなくなったPrologは、これで洞窟cはすべて探索したと判断し、その場で洞窟cを脱出してbの通路に戻りました。bにはまだ分岐点が残っていますので、そちらの探索を行います。
 これは以下のような場合も同じです。
way(right).
way(left).

a(A , B , C) :- way(A) , b(B , C).
b(B , C) :- way(B) , c(C).
c(right) :- way(right) , !.
c(left) :- way(left) , !.
 述語c/1が2つあるからといって、見た目にだまされてはいけません。述語b内の「c(C)」が洞窟cに入る記述で、そこでc(right)とc(left)の2つの道が示されるのですから、先の場合と結果は変わらないのです。当然、カットによる一方通行で洞窟探検が続行できなくなれば、入り口まで戻ってくるでしょう。
 他には、以下のような変則的パターンも考えられます。
way(right).
way(left).

a(A , B , C) :- way(A) , b(B , C).
b(B , C) :- way(B) , c(C) , !.
c(C) :- way(C).
 実行結果はこの通りです。
?- a(A , B , C).
A = right,
B = right,
C = right ;
A = left,
B = right,
C = right.
 これもまた原則論そのままです。上記の問い合わせによってまず洞窟aに入り、左右への分かれ道をひとまず右に進みます。そこで洞窟bに入り、ここでも左右への分かれ道をひとまず右に進みます。そこで洞窟cを見つけて入り、またしても分かれ道でひとまず右を選び、ここで洞窟cを突き抜けてbに戻ります。どうやら洞窟cはトンネルになっていたようです。そして、ここでカットを見つけました。カットの効果で戻って探索する必要がなくなり、洞窟bの経路探索が終わりましたので、洞窟bから帰還します。これで洞窟aまで戻りますが、洞窟aの左の道はまだ探索していませんので、分かれ道までバックトラックして探索に向かいます。
 この辺りの仕様は論理型独特のものですので、手続き型や関数型の開発経験では感覚を得づらい部分もありますが、洞窟探検のつもりで考えてみましょう。

 関数型言語が最も得意とするものは何でしょうか。
 手続き型との差異は色々ありますが、関数型といえば1にも2にもリスト処理でしょう。関数型言語の元祖であるLisp自体、List Processorの略称とされています。そもそもLispではすべてがリストなのです。関数もリスト、マクロもリスト、マクロによって置き換えられるデータもリストです。
 その他の関数型言語はさすがにそこまで極端ではありませんが、多くの言語はリストの扱いに長けています。例えば、ほとんどの関数型言語にはmap関数が用意されています。リストの全要素に1を加えたいとすれば、Common Lispなら
(mapcar (lambda (x) (+ x 1)) '(1 , 2 , 3 , 4 , 5))
 とするでしょうし、カリー化ができる言語なら
map (+ 1) [1..5]
 と書いても構いません。手続き型ならforeachが使えそうですが、そうはいかない場合もあります。JavaにはSE 5からfor-each文が導入されましたが、プリミティブ型では
int list = {1 , 2 , 3 , 4 , 5};
for(int i : list)
	i ++;
 このようなことはできません。ここでのint iはコピーに過ぎないため、変更しても意味がないのです。
 その他、関数型のリスト処理の例としてよく引き合いに出されるのが、以下のようなHaskellのコードです。
-- クイックソート
-- 見やすくするために改行をはさんでいるが
-- 正しくは qsort (key : source) と qsort [] の2行
qsort (key : source) = (qsort (filter (< key) source)) ++
	(key : (qsort (filter (>= key) source)))
qsort [] = []

-- 動作テスト
main = qsort [5 , 1 , 7 , 3 , 2 , 9 , 8 , 6 , 4 , 0 , 5 , 8 , 2]
-- 結果 : [0,1,2,2,3,4,5,5,6,7,8,8,9]
 手続き型から関数型の世界に飛び込もうとすると、まず最初にこのような「2行クイックソート」を見せられて仰天することになります。手続き型であっても、見栄えを完全に無視すれば1行や2行にまとめられるはずですが、関数型では普通のスタイルで2行なのです。
 それでは、論理型言語たるPrologはどうでしょうか。無論、Prologにもリストは存在します。さらに、関数型言語に近い性質を持っているだけあって、リストのパターンマッチ処理など一通りの機能までもが使用できます
 まずリストを作成する方法から。
get_list([1 , 2 , 3]).
 後はこれをget_list(R)のように呼び出せば、上記リストがRに格納されますので、
?- get_list(R).
R = [1, 2, 3].
 無事に結果が得られます。なお、リストを変数に代入するには「=」を使用しましょう。「is」を使うとエラーが発生します。
 関数型言語でおなじみのパターンマッチも容易です。Lispのcar/cdr及びconsを作成するには、以下のように記述します。
car([X | _] , X).
cdr([_ | XS] , XS).
cons(X , XS , [X | XS]).
 実行すると次のようになります。
?- car([1 , 2 , 3] , R).
R = 1.

?- cdr([1 , 2 , 3] , R).
R = [2, 3].

?- cons(1 , [2 , 3] , R).
R = [1, 2, 3].
 パターンマッチの際、先頭から複数の値を取る記法も用意されています。以下はリストの先頭2つを取り、それを足し合わせる述語です。
?- plus([1 , 3 , 7 , 15] , R).
R = 4.
 これでパターンマッチが行えましたが、これだけでは面白くありません。せっかくパターンマッチをするのであれば、リストをforeachのように捜索する記述も行ってみたいものです。ここでは「リストの全要素の合計」を求める述語を書いてみましょう。
 末尾再帰を使わなければ、以下のようなコードになるでしょう。
sum([X | XS] , R) :- sum(XS , S) , R is S + X.
sum([] , 0).
 この種の処理では末尾再帰が通例ですので、末尾再帰を使うのであれば、
sum(XS , R) :- in_sum(XS , 0 , R).
in_sum([X | XS] , V , R) :- N is V + X , in_sum(XS , N , R).
in_sum([] , R , R).
 こうなります。
 いずれも呼び出し方は同じで、以下のようになります。
?- sum([1 , 2 , 3 , 4 , 5] , R).
R = 15.
 他のリスト操作も考えてみましょう。この記事の最初で「すべての要素に1を加える」処理が出てきましたが、Prologでこのような述語は書けるのでしょうか。
add(XS , RS) :- in_add(XS , [] , RS).
in_add([X | XS] , YS , RS) :- Y is X + 1 , in_add(XS , [Y | YS] , RS).
in_add([] , YS , RS) :- reverse(YS , RS).
 関数型におけるリスト処理のお手本のようなコードです。まずリストの先頭から値を1つ取り、それに1を加えて結果用リストの先頭に加えます。このままではリストが逆さになっていますので、Prologに用意されている述語であるreverse/2を使って反転しています。
 なお、もしreverse/2がなかったとしても、これは以下のようにして簡単に作れます(すでにreverseが存在する環境で名前がぶつからないようにするため、末尾にアンダーバーを入れてあります)。
reverse_(XS , RS) :- in_reverse_(XS , [] , RS).
in_reverse_([X | XS] , YS , RS) :- in_reverse_(XS , [X | YS] , RS).
in_reverse_([] , RS , RS).
 無事にプログラムが完成したところで、述語を実行してみましょう。
?- add([1 , 3 , 7 , 15] , RS).
RS = [2, 4, 8, 16].
 簡単なものです。
 次に、取り上げ忘れていたfail機能について。以前に
some(any).
 このような述語は、
some(any) :- true.
 これと同じであると述べました。
 Prologにはこれの対となる述語も用意されています。true/0の反対といえば、通常の言語からすればfalse/0が妥当なところで、実際にSWI-Prologではfalse/0も用意されています。しかし、false/0はSWI-Prologの独自拡張であるらしく、GNU Prologでは「そのような述語はない」旨のエラーが発生してしまいます。
 Prologにおいてtrue/0の対となる述語はfail/0です。この述語はその名の通り、マッチをその場で確実に失敗させます。迷路の例で言えば、「この先には進めません。引き返してください」と立て札が立ててあるようなものです。世の中にはひねくれた人間がいるもので、大抵は立て札を無視して進もうとする人が現れるものですが、大抵はろくな結果になりません。わざわざ「このはしは渡れません」と書いてあるのに、「はしを渡ってはいけないのだから、中央を渡ればよい」などと訳の分からない理屈によって橋を渡ろうとすると、大抵は途中から完全に通れなくなっており、無駄足になってしまう場合がほとんどです。当然ではありますが、Prologにひねくれ者や詭弁屋はいませんので、failを見つけた時点で必ず引き返してくれます。
 failはあくまで「道を引き返すよう書かれた立て札」に過ぎないため、failを見つけた時点で探索が終了するわけではありません。一旦引き返して分岐点まで戻った後、まだ入っていない道があれば、そちらも探索します。あまり利用価値はないかもしれませんが、もしその場で述語内部の探索自体を終了させたければ、
! , fail.
 このような記述となりそうです。カットによって通路が一方通行になっており、さらにその先は立ち入り禁止なのですから、もし公道でこれが行われれば大バッシングは必至ですが(しかもそのような場所に限って取り締まり警察官を配置)、Prologでは捜索を打ち切るだけですので、問題はありません。
 このfail、単に「条件を失敗させる」記述としても使用できるのですが、Prologをある程度手続き風に記述する際にも用いられているようです。PrologにもIO処理は存在し、標準出力への書き込みはwrite/1、改行の書き込みはnl/0、一方で標準入力からの読み込みはread/1で行われるのですが、このようなIO述語を使用すれば、条件が失敗したとしても出力や入力はなされますので、何らかの効果が得られます。
 例えば以下のような述語があるとして、
languages(prolog).
languages(ocaml).
languages(lisp).
 論理型言語の特性を用い、言語すべてを取得するのは簡単です。ただ単に以下のように問い合わせるだけです。
?- languages(R).
 複数の結果が得られますので、後はセミコロンですべて表示するだけです。  それでは、複数の結果をセミコロンで表示するのではなく、すべての結果を一気に標準出力に表示したい場合はどうするのでしょうか。実際、このような処理は手続き型言語では頻繁に行われますし、関数型でもHaskellでやるのは少々面倒ですが、OCamlなどでは普通に行われます。Prologでもこのような処理には需要があるはずです。
 今までになかった問題だけに、一見すると悩んでしまいそうですが、何のことはありません。failを使用すれば良いのです。
?- languages(R) , write(R) , nl , fail.
prolog
ocaml
lisp
false.
 簡単に解説を。まずlanguage(R)の分岐点に差し掛かりますが、道がprolog、ocaml、lispの3つに分かれています。最初にprologの道に入り、道なりにあった述語write/1によってそれを標準出力に書き込み、nl/0によって改行を書き込みます。しかし、ここで「立ち入り禁止」の看板が見つかりましたので、分岐点まで戻ります。分岐点にはまだ入っていない道がありますので、次はocamlの道に入って同様の操作を行い、さらにはlispの道にも入ります。これで探索は終わりましたので、falseを返して終了します。
 つまり、write/1などの述語によってIO処理を行いつつ、探索処理自体はfailで失敗させるようにすれば、パターンの列挙が可能になるのです。これは習得しておくと役に立つ概念ですので、頭に入れておいて損はないでしょう。
 次に、Prologで「A = 1 + 2」を実行すると、なぜかAは「3」ではなく「1 + 2」になりますが、これの使い道について。Prologでの代入(らしきもの)には「=」と「is」の2種類がありますが、これらの効能がそれぞれ異なるのは以前に述べました。
 ところで、Prologには他にも代入がなされるケースがあります。述語の変数に対して値を渡す際と、述語のパターンマッチで値を受け取る際です。それぞれ以下のようなケースが該当します。
% 値を渡す
give(R).
?- give(100).

% 値を受ける
take(100).
?- take(R).
 これらの処理においてなされる代入は、「=」のものと同じです。したがって、takeを
take(R) :- R = 100.
 このように書いても構いません。
 これが何を意味するのかといいますと、この動作には前回の記事でも触れましたが、述語の引数として「1 + 2」を渡すと、述語の側は「3」ではなく「1 + 2」を受け取るのです。つまり、Aに1を加えた値を述語some/1に渡したければ、普通の関数型言語のように「some(A + 1)」としてはいけません。「B is A + 1 , some(B)」としなくてはならないのです。
 逆に言えば、述語の側は渡したものを「そのまま」受け取ってくれるのですから、実装の一例として以下のような述語が作成できます。
when(EXPR , CODE) :- EXPR , ! , CODE.
 これは「EXPRの条件を満たした場合のみ、CODEを実行する」述語です。EXPRとCODEの間にカットがあるのは、もしEXPRが複数の道を有する分岐点になっていたら、何度もEXPR以降の処理を実行してしまう恐れがあるためです。
 これを使って、以下のような問い合わせを行ったとしましょう。
?- A = 1 , B = 0 , when(A > B , write('OK')) , fail.
OK
false.

?- A = 1 , B = 2 , when(A > B , write('OK')) , fail.
false.
 上記の通り、面白い結果が得られます。1つ目の引数の条件がtrueにならない限り、2つ目の引数の述語は全く実行されないのです。仮に実行されるのであれば、whenの1つ目の引数が失敗してもメッセージが表示されるはずですから、2つ目の引数が実行されていないのは明らかです。
 これはいわば、Lispのマクロのようなものです。「=」型の代入は、述語が実行されて結果が代入されるのではなく、述語そのものが代入されますので、
when(A > B , write('OK'))
 この呼び出しであれば「EXPR = A > B , CODE = write('OK')」となるでしょう。くどいようですが、この呼び出しの時点ではまだ述語は実行されません。whenに入ってはじめて、まずは「A > B」が実行され、それがtrueであればwrite('OK')が実行されます。
 この仕様のおかげで、PrologでもLispのマクロのようなテクニックが使用できるのです。一見すると意図が分からない仕様にも、実は深い意味があったのです。せっかくお膳立てがなされているのですから、この仕様を用いて手続き型にありがちな制御構文を書いてみましょう。まずはifから。
if(EXPR , CODE , ELSE) :- (EXPR , ! , CODE) ; ! , ELSE.
 まずEXPRで渡された述語を評価します。もし真であればカットを通ってCODEに移り、偽であるならカットを通ってELSEに移ります。こちらでもカットがなければ後戻りしてしまい、EXPRが真であってもCODE実行後にORの先にあるELSEまで実行してしまいます。気をつけましょう。使い方はLispのifと似たり寄ったりで、1つ目の引数の評価が真であれば2つ目、偽であれば3つ目の引数の述語を実行します。
?- if(1 > 0 , write('expr is true') , write('expr is false')).
expr is true
true.

?- if(1 < 0 , write('expr is true') , write('expr is false')).
expr is false
true.
 次に、単純な回数指定型ループを。
for_loop(MAX , CODE) :- in_for_loop(0 , MAX , CODE).
in_for_loop(I , MAX , CODE) :- I < MAX , CODE ,
	J is I + 1 , ! , in_for_loop(J , MAX , CODE).
 単純なループですが、CODEには述語を渡せます。
?- for_loop(5 , (write('Spam!') , nl)).
Spam!
Spam!
Spam!
Spam!
Spam!
false.
 fail/0の他に用いられる述語として、repeat/0なるものもあります。これは無限回廊のようなもので、いわば永久に探索が終了しない分岐点です。推測ですが、実装はおそらく以下のようなものではないでしょうか。
repeat_ :- true ; repeat_.
 仮に以下のようなプログラムを書き、
eternal(R) :- repeat , R = 10.
 問い合わせたとします。
?- eternal(R).
R = 10 ;
R = 10 ;
R = 10 ;
R = 10 ;
R = 10 .
 セミコロンを打ち続ける限り、永久に同じ結果が返ってきますので、ピリオドを打って終了しましょう。
 もしrepeatの動作が先の通りなら、これは次のように解釈できます。まず「true ; repeat」はORでつながれていますので、これはtrueの道とrepeatの道の2通りがある分岐点となります。まずはtrueの道に入り、trueですからそのまま道を進んでその先の探索を行います。探索が終わったら、ここの分岐点のうちrepeatの道にはまだ入っていませんので、そちらに向かいます。ところが、たどり着いたのは同じ分岐点でした。どうやら同じところに戻ってきてしまったようです。しかし、普通の人なら数回もすればいい加減に気づいて探索をやめるところですが、探索を打ち切ってはならないのがPrologの定めです。したがって、また同じ処理の繰り返しとなります。
 この無限回廊から抜け出すにはカットを使用します。trueの道を探索しつくした後、戻ってきてrepeatの道に入るから無限回廊となるのであって、trueの道の途中が一方通行になっていれば無限回廊に戻る必要がなくなりますので、カットの先を探索しつくした時点で処理が終了します。一方、途中で再びループの先頭に戻りたい(いわゆるcontinue)場合には、failで失敗させてrepeatまでバックトラックさせる方法があります。
 repeatには注意点もあります。repeatは無限回廊で、それゆえに全経路を探索することはできません。この性質により、repeatより以前にあった分かれ道に未到達経路があったとしても、repeat以前へのバックトラックはできません
 このような分かれ道の述語があるとして、
way(right).
way(left).
 以下のように問い合わせたとしましょう。ここまでの内容を正しく理解していれば、これの結果は考えるまでもなく分かるはずです。
?- way(A) , way(B).
A = right,
B = right ;
A = right,
B = left ;
A = left,
B = right ;
A = left,
B = left.
 当たり前のコードを書くなと怒られそうですが、それではway(A)とway(B)の間にrepeatをはさんだ場合はどうでしょう。
?- way(A) , repeat , way(B).
A = right,
B = right ;
A = right,
B = left ;
A = right,
B = right ;
A = right,
B = left ;
(以下、セミコロンを打つ限り無限に続く)
 way(A)では左の道に入っていないようですが、なぜでしょうか。一言で言えば、repeatをさかのぼってのバックトラックはできないためです。
 理由を解説しておきましょう。まずway(A)の分岐で右に進みます。そして、その先にあるのがrepeatの無限回廊です。trueの道とrepeatの道のうち、まずtrueの道に進みます。その先でway(B)の分岐を発見し、まず右に進み、次に左に進みます。これでway(B)の全経路を探索したので、バックトラックで無限回廊まで戻ります。ここの分岐のうち、trueの道は探索が終わったところですので、次はrepeatの道へと進みます。無限回廊ですから同じ場所に戻されるのですが、それでも探索をやめてはいけないのがPrologの定めです。またもtrueの道に進み、バックトラックし、repeatの道に進んで無限回廊を探索し続けます。永久に経路の探索が終わりませんので、それ以前へのバックトラックも機能しません
 repeatを使いつつ、way(A)とway(B)の経路探索も行いたいのであれば、以下のようになるでしょう。
way(right).
way(left).

a(A , B) :- way(A) , b(B).
b(B) :- repeat , ! , way(B).
 way(B)の前にカットがあるため、先のように無限ループには陥らず、way(B)の左右の道を探索した後にbを脱出します。したがって、結果は当然
?- a(A , B).
A = right,
B = right ;
A = right,
B = left ;
A = left,
B = right ;
A = left,
B = left.
 こうなります。
 repeatの構造を応用すると、forやforeachといったものも作成できます。例えばforeachが欲しければ、
foreach([A | XS] , R) :- R = A ; foreach(XS , R).
 こうなります。1つ目の引数がリスト、2つ目が取り出した値を受け取る変数です。Prologでは基本的に、1つの述語呼び出し内では変数の中身は一意でなければならず、「A = 1 , A = 2」なる記述は失敗しますが、逆に言えば「違う呼び出し内」でなら別の値を割り当てても構わないのですから、このような記述が可能です。
 実際に使用してみましょう。
?- foreach([1 , 2 , 3] , X) , P is X * X , write(P) , nl , fail.
1
4
9
false.
 確かにforeachが実行されています。最後のfailがなぜ必要かが分からない方は、この記事を最初から読んでみましょう。結論から言えば、failは別に存在しなくても動作はしますが、いちいちセミコロンを押して次候補を表示しなくてはなりません。また、repeat同様にカットでループを打ち切ったりもできます。
 このままではあまりに理解が難しいコードですので、例によって探索に例えた解説をしておきましょう。まず「foreach([1 , 2 , 3] , X)」が呼び出されると、Prologはforeach([A | XS] , R)に入っていきます。ここでRには未確定の変数Xが渡されていますので、これは当然未確定となります。foreachに入ると現れるのが「R = A ; foreach(XS , R)」なる分岐点です。まずはR = Aの道に進むことにして、Rは未確定の変数ですので、RにはAを代入します。R = Aはマッチしましたので、foreachのトンネルを抜けてforeach以降の探索を始めます。その探索が終わったら、先の分岐点までバックトラックを行い、もう一方の分かれ道であるforeach(XS , R)に入ります。以下、リストを全部取り出すまで無限回廊が続きます。
 COBOL使いの方には、これなどいかがでしょうか。
perform(VARYING , FROM , BY , UNTIL) :- FROM =< UNTIL ,
	(VARYING = FROM ;
	NF is FROM + BY , perform(VARYING , NF , BY , UNTIL)).
 多少はCOBOLらしさが出せたでしょうか。使い方はCOBOLとほぼ同じです。
% PERFORM VARYING IDX FROM 1 BY 3 UNTIL IDX > 10
?- perform(IDX , 1 , 3 , 10) , write(IDX) , nl , fail.
1
4
7
10
false.
 ちなみに、このような書き方もできたりします。参考までに。
perform(FROM , FROM , _ , UNTIL) :- FROM =< UNTIL.
perform(VARYING , FROM , BY , UNTIL) :- FROM =< UNTIL ,
	NF is FROM + BY , perform(VARYING , NF , BY , UNTIL).
 上の「perform(FROM , FROM , _ , UNTIL)」により、引数の1つ目と2つ目を同じ値と特定していますので、これがVARYING = FROMの作業を代行しています。このように書いたとしても、やっていることはほとんど同じです。もし違いがあるとすれば、「FROM =< UNTIL」が2回評価される程度のものでしょう(当然ながら同じ結果となるため、動作は特に変化しない)。Prologは結構色々な書き方ができますので、好みの方法で実装しましょう。
 今回はなかなかすさまじい内容となりましたので、この辺までにしておきましょう。つくづく簡単なプログラム言語など存在しないものです。
カテゴリ [開発魔法][社会問題][経済・知的財産] [トラックバック 0][コメント 0]
<- 前の記事を参照 次の記事を参照 ->

- Blog by yamicha.com -