最近の若いもんはマシン語をしらん、けしからん、みたいな話が盛り上がってますね。

そんな若くもないのですが(22歳)、中学のころにはWindows95があって、携帯電話を持っていて、高校生のころには既にADSLなどの高速回線を普通に使っていた、そんな世代の俺の考え。まぁ俺はプログラマでもなんでもないんだけど。

全体的な結論

全体的な結論を先に言うと、個人的にこういう原点回帰的な話というのはそんなに好きじゃない。もっと高次で活躍する人が増えてもいい、と思っているから。一人の人間の時間は有限で、それを高次レイヤにつぎ込んでもっとおもしろいことができるなら、そっちにつぎこめばいいんじゃないかな。俺はそれは全然アリ派。たとえば、音楽でいうと、DTMしかできないやつは音楽できる顔すんな、みたいなのが嫌い。DTMしかできなくてもいい曲かく人なんていっぱいいるし、それでいいと思う。なんていうか、努力とかよりも、感性にあこがれるタイプだからかな。上のレイヤからはいっても、きっと基礎を固めてちゃんとやりたい、それが必要だ、と思えば人は勉強する。だからあえて言うこと(必要だと言い切ること)でもないんじゃないかなあ。現に、だいたいコンピュータ技術者というものは最終的に下のレイヤへ下がっていく人が多いですよね。

マシン語とかについて

きっと議論を呼んでいるのは「絶対必要」みたいに断定してしまったからで、知っていればこんないいことがあるんだよ、という感じならみんな納得するんじゃないかなあ。

上に書いたように俺の世代ってのは中学ですでにWindows95があってVBやらVCやらDelphiがあった世代で。そんなに苦労しなくても見栄えのいいGUIアプリがかける環境があったわけで。当然意識しないとマシン語とかアセンブラには触れない。俺はたしかJAVAからプログラミングに入ったけど、別にマシン語知らなくても全然大丈夫だった。

んでさらにはWebアプリの台頭。Webアプリを書いているときにマシン語をしらないから、という理由で困ったこともないし、新しい言語を覚えるときに困った覚えもない。つまりプログラマでも書くプログラムによってはそんなに必要ない、ということ。そういう時代まで、先人達の努力でやってきた、ということ。暇があるなら低レイヤを覚えておくにこしたことはないけど、他に覚えるべきことがあるなら、そっちを勉強したらいいと思う。

ただ、知っといたほうがいろいろいいことがあるのも事実。なので覚えたい人はがんばりましょう、ということで。

同じことを書いてる人もいるけど、むしろアセンブラとかにこだわりを持っている人のほうが、「ひどい」コードを書くこともあるよね。処理効率を優先しまくって可読性を落としたりとか、何をやってるのかわからないのがイヤ、と自分で必要ないものまで書いたりとか。

俺と低レイヤ技術

とそんなことを書きつつ、実は低レイヤも好きな俺。すみませんすみません。個人的に低レイヤの(特にCPUとか。ネットワークとかじゃなく。)ことを勉強したいなら、エミュレータは一度書いてみるべきだと思う。一個8bitCPUのエミュレータを書いて、そのCPUの逆アセンブラを書いて、デバッガ作って、できれば自分でアセンブラを書いて、アセンブリ言語をマシン語に落として、そのコードを実行させてみれば、CPUの基礎はかなりわかると思う。データがそろってる8bitCPUならそんなに苦労することなくかけるので、一度書いてみてはいかが。アセンブリ言語の書き方も、割り込みがどーたらも、なんMhzとかってなんなの、とかサイクルってなにとかメモリってどうなってんの、DMAってなにがうれしいんだよとかそういやビット演算ってなんの役にたつの、とか色々一気に疑問が解決する。それがわかっていればあとは順をおってCPU関連技術を勉強していけば理解もはやい気がする。自分で命令セットまで考えてそのCPUをソフトで実装すればもっと完璧。

実装言語はなんでもいいんじゃないかなあ。手前味噌だけど、 Pythonでもエミュレータを書こうと思えばかける わけで、PerlでもRubyでもJavascriptでもいいと思う。動作速度よりも理解する過程が楽しいかと。ちなみに自分の書いたPythonでのNESエミュレータだとCPU(6502)とメモリ関連で、簡易逆アセンブラ込みで1000行ほど。速度を犠牲にすればもっと短くかける。

あと、これも書かれてるけどむしろネットワークとか、DBとかのほうがよっぽど低レイヤの知識が必要だよなあ。10BASE-Tと100BASE-Tでなんでつなげるリピータハブの数が違うのかとか、これならどれだけスループットが確保できるか、それをわかるためにもCSMA/CDはなんたるかとか、実際どうやってケーブル上で衝突を検出してんのかとか色々わかってないと困るしねえ。他のネットワーク技術でも一緒。生のパケット(orフレーム)を見なけりゃいけないことも多々あるし。ソフト使ってちゃんと設定がかけます、だけだと意味ない。OSIの層を上から下までカバーしないと。そういった意味でもネットワークっておもろい。


ちょっと前にjavascriptで構文解析とかがはやった気がするので、javascriptのリハビリがてらかいてみた。

ググってみると

あたりがあるのだが、まぁ勉強ということで。javascriptらしく書いてみようかと。

ということで、モナドがどーたらとか難しい話はまぁおいておいて、簡単に値がとりだせますよ、という見栄え重視で作ってみた。基本的な機能しかない。けど拡張するのは簡単。せめて相互再帰くらいは実装したほうがよかったかな。まぁ、こんなの真剣に使う人もいないと思うので、要望があればってことで。ちなみに依存するライブラリはありません。

ダウンロードInforno.Parsec

たとえばこんな感じにCSVのパーサが定義できる。withを使ってDSLっぽくしてみた。

 1var CSVParser = Inforno.Parsec.Parsers.define(function(){with(this){
 2  this.chars = chrLike(function(c){ return c != '' && c!=',' && c!='\n' && c!='"';});
 3  this.quote = chr('"') 
 4  this.quoteInQuote = str('""') .ret(function(){return '"';}); 
 5  this.charInQuote  = chrLike(function(c){ return c!='"';});
 6  this.quotedField  = quote .and (rep((quoteInQuote) .or (charInQuote))) .and (quote)
 7                      .ret(function(q1, cs, q2){
 8                        return cs.join("");
 9                      });
10  this.field        = rep1(chars) .ret(Return.str)
11  this.record       = sep( (field) .or (quotedField), chr(","), true) .ret(function(fields) {
12    return {fields: fields};
13  })
14  this.csv          = sep(record, chr("\n"), true) .and(eof) .ret(function(records) {
15    return {records : records};
16  })
17}});
18
19var testCsv = [
20'"aaa","b',
21'bb","ccc",zzz,"y""Y""y",xxx'
22].join("\n");
23
24var parser = new CSVParser(testCsv);
25var parseResult = parser.csv.parse()
26if(parseResult.success()) {
27  var records = parseResult.result[0].records;
28  for(var i=0,l=records.length;i<l;i++){
29    alert("row("+i+")    "+records[i].fields);
30  }
31}

実はパーサコンビネータって簡単にかけるんだけど、世間的にちゃんと認識されているのかなあ。思うに、パーサコンビネータといえばHaskell界隈であり 、関数型界隈であり(もちろんちゃんとJAVAとかの実装もあるんだけど)、モナドでありそういうところって専門用語が多いから「ふつうの」プログラマからは簡単に見えてないような気がするなあ。


でましたね。 Prototype 1.6.0 release candidate

WEB界隈から離れてしばらくたちますが、またいつWEB界隈に戻るかわからないので一応追ってます。

1.6ではついにClass周りに手が入りました。Prototype.jsといえばシンプルすぎるClass周りとプロパティをコピーするというなんちゃって継承がウリ(?)だったわけですが、1.6からは違います。もう オレオレクラス定義ライブラリ をわざわざ使わなくても大丈夫。

公式にも例がありますが、こんな感じでちゃんと継承できるようになりました。

 1var Animal = Class.create({
 2  initialize: function(name) {
 3    this.name = name;
 4  },
 5  eat: function() {
 6    return this.say("Yum!");
 7  },
 8  say: function(message) {
 9    return this.name + ": " + message;
10  }
11});
12
13var Eatable = {
14  eaten : function() {
15    return this.say("help me!!!");
16  }
17}
18
19var Mouse = Class.create(Animal, {
20});
21//syntax sugar for Object.extend
22Class.mixin(Mouse.prototype, Eatable);
23
24// subclass that augments a method
25var Cat = Class.create(Animal, {
26  eat: function($super, food) {
27    if (food instanceof Mouse) return [food.eaten(),$super()].join("\n");
28    else return this.say("Yuk! I only eat mice.");
29  }
30});
31
32var a = new Cat("Tama");
33alert(a.eat(new Mouse("Nezumy mouse")));

単にプロトタイプチェーンをつなげるだけではなくて、オーバライドされたメソッドの引数名を取得して(toStringしてgrepですね)、$superだった場合、自動的に親クラスのメソッドを$superとして渡してくれます。地味に便利。

あとはsyntax sugarとしてClass.mixinがあります。まぁObject.extendなんですが、こっちの方がわかりやすいですよね。  

 

  そのほかもいっぱい機能が追加れさてれてますね。個人的には document.observe("contentloaded", function() { ... }) て感じでサポートされたDOM完了時点でのイベントと、

1$("container").observe("titleChanged", function(event) {
2  this.highlight({ duration: 0.5 });
3});
4
5$("title").fire("titleChanged");

って感じのカスタムイベントが必ず使いそうな機能かな。


資格の勉強とかもそろそろしなきゃなー、と思いつつ、Scalaでパーサコンビネータライブラリがついたので、Schemeの処理系でも実装したいなあ、と思い始めてる今日この頃。