krのコメント: コードウェイナー・スミス (スコア 1) 23
# お約束なのでID。
アナウンス:スラドとOSDNは受け入れ先を募集中です。
「禅問答的に #ATS2 の型理論を説明してみたよ http://togetter.com/li/752948 」というtogetterのまとめが話題のようだ。
通常の型理論では、まず型を定義して、その型のコンストラクタによって値を生成する。ところがこの型理論 "Applied Type System" では既に存在する値に型を割り当てている。 (Applied Type)
この型理論のエポックメイキングなところはコンストラクタを型理論の中で不要にすることによって、ヒープを使わなくても型の実装ができるところだろう。
#define ErrorCheck(f) if ((err = f) != 0) goto fail
でおk
それは潜在的に危険なコードです。
ErrorCheck()を使う側で、以下ようなコードを書くと、
if (.../*条件A*/)
ErrorCheck(...);
else
.../*処理B*/;
この見た目と違って、実際のマクロ展開は(改行と字下げを付けると)、
if (.../*条件A*/)
if ((err = ...) != 0)
goto fail;
else
.../*処理B*/;
となり、「処理B」が「条件A」のelse部でなく、「(err = ...) != 0」のelse部にくっついてしまいます。
else節は最も近いif文にくっつくという構文規則になっているので、 マクロにelse節無しの剥き出しのif文を埋め込むのは危険なのです。
do〜while(0)で囲めば、このような副作用が無くなるので、より安全なマクロ定義となります。
面白そうなので、自分も(好みにより言語はHaskellで)書いてみようと思ったら、
すでに沢山あってちょっとクラクラしました……。
No guessingってのがokkyさんと似た動機で書かれた版かな。
リスト中のアルゴリズムを順に試して、
うまく行ったらまたリストの最初から繰り返す、
という造りも同じようです。
Sudoku Solver等、
似たようなプログラムが見付かるところを見ると、
やはり誰しも書きたくなる題材なのですかね。
時間ができたら自分でも遊んでみたいと思います。
面白いネタに気付かせて戴いて有難うございました。
古い格言に曰く、プログラムは思った通りではなく、書いた通りに動く。
@arrayを未定義値にしたいなら、
@array = undef;
ではなく
undef @array;
と書くべきだったという話ですかね。
undefの返値がLISTコンテキストで()と解釈されて欲しいと思うこともあるかもしれませんが、
それはそれで、
select undef, undef, undef, 0.1;
とか書けなくて不便という。
ある種のLISPにおけるnilの扱いと混同しがちですが、
結局のところ、Perlにおける()とundefを理解して適切に使い分けるのが吉かと思います。
混乱したらperldata(1)やperldoc -f undefを読み返しましょう。
すでに自力で答を得ているかもしれませんが御参考までに。
$filename = "file space";
open (MD5,"md5sum $filename |");
のような2引数のopenでパイプを作ると次のように動きます。
1. Perlが変数$filenameを展開。("md5sum file space |")
2. Perlが末尾のパイプ記号を見て、残りを/bin/shに渡す。("md5sum file space")
3. /bin/shが文字列を空白で区切る。("md5sum", "file", "space")
4. /bin/shが"md5sum"を探して引数("md5sum", "file", "space")を渡す。
5. md5sumが引数を見て"file"と"space"のMD5を計算しようとする。
Perlが/bin/sh経由でmd5sumを実行するので、 空白に限らず、/bin/shの特殊文字が意味を持ってしまいます。
例えば、カレントディレクトリの全ファイルのMD5を計算しようとして、
#!/usr/bin/perl --
# 注: 危険なスクリプト
foreach my $filename (<*>) {
open(MD5, "md5sum $filename |");
print <MD5>;
close(MD5);
}
なんてスクリプトを使ってしまうと、例えばカレントディレクトリに、
$ touch "<'file space'|rm -rf *"
なんてやって変な名前のファイルを仕込まれていた場合に泣きます。 良い子は真似しないでね。
話を戻すと、そもそもPerlが/bin/sh経由でmd5sumを呼び出すのが悪いので、 もっと安全にパイプコマンドを作れば良いのです。 では、どうするか? 悩んだらマニュアルを読みましょう。RTFM!! この場合はopenで悩んでいるので、
$ perlfunc -f open
とかやって読みます。するとパイプの説明で盛んに「perlipcを読め」と書いてあるので、そっちも読みます。
$ man perlipc
すると"Safe Pipe Opens"節に、 shellに邪魔されない方法が色々書いてあります。好きなやり方を選びましょう。TMTOWTDI.
Ubuntu 11.10ならこんな感じで動くはず。
open(MD5, "-|", "md5sum", $filename)
ちなみにsystemとかbacktick(qx//または``)とかも同様の問題を孕んでおり、 解決策も似ているので以下RTFM。
では引き続きPerlプログラミングをお楽しみ下さい。enjoy!
AppleがMacからHyperCardを消した理由についての考察が本家/.にて取り上げられている。
HyperCardのポテンシャルを誰よりも理解していただろうジョブズは、HyperCardを無きものとしてしまった。その後も復活の要望は高く、市場もあったにも関わらず、類似ソフトウェアが登場することは無かった。
理由はHyperCardがAppleの作ろうとしている世界にそぐわなかったことにあるとこのブログでは指摘している。その世界とは、今はほぼ消えつつある「コンピュータを『使うこと』と『プログラミング』の境界の薄い世界、パーソナルコンピュータが単なる高価なビデオ付き電話ではなく、自分の頭の中を増幅してくれる端末である世界。そしてそれはAppleの囲い込み戦略が実現し得ない世界でもあったのだと。
HyperCardが存続されていたならば、iOS端末やその他Apple製品は現在のように存在していただろうか?ふと考えさせられる。
UNIX系OSであるMINIXの開発者であり、Linus Torvald氏とOSについて激論を交わしたことでも知られるAndrew Tanenbaum(アンドリュー・タネンバウム)氏が、LinuxFr.orgとのインタビューに応じ近況を語っている(gihyo.jpの記事)。
相変わらずLinuxに関しては攻撃的な物言いで、「Linuxは5%程度のシェアしかないのに成功したというのはおかしい」などとこけ下ろしている。ともあれ、MINIXは順調に開発が進められており、組み込みシステムへの対応強化や可用性の向上など、今後も機能強化が続けられる模様。
Firefox 9.0β3のWindows64bit独自ビルドを公開しました。
私もその辺がよく分からないのですが、
初期化されたか=保持されている値が有効か否かのフラグを
アドレス値とは別に持たせるべきだったとでもいうのでしょうか?
そうではなくて、 (non-nullな)参照型が決してnullになり得ない言語仕様にしておけば良かった、 ということでしょう。
といっても、nullに慣れ親しんでしまった人には、 なかなか想像し難いものがあるかもしれません。 例えば、こう考えてみてはどうでしょう。 Javaにそもそもnull定数が無く(nullが予約語でなく、 たとえnullと書いてもコンパイル時に未定義変数エラーになる)、 すべての変数に初期化が必要で、 nullを返すようなライブラリ関数も無かったとしたら? 参照型変数が必ず有効なオブジェクトを参照するように初期化され、 オブジェクトを明示的にfree()/deleteで開放できないとしたら、 ポインタの先を参照した時、そこには必ず値があります。 ポインタをそもそもnullにする方法が用意されていないとしたら、 ポインタがnullかどうかのチェックをする必要もありません。
「えー、でも、それじゃどうやって、値が無いことを示すのさ?」
値が無いかもしれないことを示す必要がある時だけ、 nullableな型を使いましょう、というのが、答のようです。
少なくとも、 ホーア氏のプレゼンテーション概要にある Spec#は、 そのようになっています。
Spec#では、ポインタ型に2種類あって、 nullableなポインタ型か、non nullなポインタ型を宣言できます (C#では値型Tのnullable型をT?と書けますが、それと反対に、Spec#では参照型Tのnon null型をT!と書けます)。 この二つは、コンパイル時の型チェックにより、混ざらないようになっているので、 non nullポインタ型については、 実行時にnullかどうかのチェックをする必要はありません。 参照先に有効な値が存在することは、コンパイル時に保証されているわけです。 non-null型を使うのをサボってnullableなポインタばっかりにしたら、 結局今までと同じじゃん、という気もしますが。 詳しくはDeclaring and Checking Non-null Types in an Object-Oriented Language(注: PDFです)参照、ということで。
実はこのようにポインタ型を2種類持つ言語はSpec#が最初というわけでもなく、 他にも例えば Adaの 参照型も、"not null"を指定するかどうかで、2種類の参照型を区別できます。
Spec#は、独自の革新的なアイデアが入っているというわけではないものの、 過去の様々な言語の良いとこ取りを目指しているようですね。 Eiffel風の契約プログラミング向きの 書法があったりして、なかなか面白いです。
件のホーア氏のプレゼンについては、 以前Lambda the Ultimateでも取り上げられていました。 そこでもいくつか興味深いコメントが付いていたので、参考にどうぞ。 Adaでもnot null指定ができるというネタはここから頂きました。 「nullableばっかり使ったら同じじゃん問題」に対応した言語については 別のコメントに書いたのでそちらもどうぞ(長文ばかり(_ _))。
おせっかいモードで補足すると、ML系の言語では、 「決してnullにならない」型と、 「nullになり得る(つまり値が無い場合もある)」型を使い分けることができる、 という話ですね。
Standard MLの
option型や、
HaskellのMaybe型が、
「値が無い場合もある」型として使われます。
コンパイル時の型チェックにより、
「場合分けして、値が有る場合」という場所でしか直接の値を参照できないので、
値が無いのに間違えて値を取り出そうとすることはありません。
# 一応「値があればそれを取り出し、値が無い場合は例外を発生せよ」というライブラリ関数も用意されているので、
# Javaのぬるぽ^H^H^HNullPointerExceptionと同様の動作をさせることも選べます。
ML系言語に馴染みがない人のために、 比較的メジャーな(?)命令型言語から似たものを探すと、 C#の nullable型のようなものを連想すると分かりやすいかもしれません。
option型やMaybe型は、参照の際に、 値が無い場合についてのケアをしないと、 必ずコンパイラに怒られるようになっています。 だから安全、というわけですが、 とはいえ、値を使う度に場合分けをするのも面倒です。 そこで例えばC#では、 nullableに対する演算を別途定義することで、 面倒な場合分け無しに、ちょっとしたコードを書ける工夫がしてあります。 Haskellでは、これをもっと一般化させていて、Maybeは Monadとしても使えるために、かなり複雑な計算でも、 驚くほどすっきりと書けたりします(うまくMonadで書ければ、ですが)。
ということで、nullにお悩みなら、ML系言語をどうぞ。:-)
前回のエントリの続きです。
もうちょっと高速化できないか考えてみます。
どんなプログラムでも、高速化の要は「頻繁に実行される箇所を少しでも速くする」ことです。 そういう点では、tanakh氏が試みていたように、文字入力処理の高速化を図るのは正しい方向性と言えます。 しかし、そこに手をつけると、一通りの入出力処理をすべて再実装することになり、大変な変更が必要になるのは目に見えています。
もっと楽をして速くできる箇所があれば、それに越したことはありません。そんな目で再びprog8を見てみると、 整数の加算やリストの分解と言った、比較的軽い処理の中にあって、なんとなくisSpaceが目立っていることに気付きました。
海軍に入るくらいなら海賊になった方がいい -- Steven Paul Jobs