窓使いの憂鬱 (心残りVer.)

前回のエントリSchemeことはじめ - 外付Web海馬から、Schemeに限らずいろいろなプログラミング言語や文章をEmacsで書くようになりました。
今まではWindowsキーバインドが当たり前の状態だったので、特に不満は感じていなかったのですが、Emacsのそれに慣れてしまうと、もう病み付きです><
矢印キーや、BackSpace、DeleteやEnterまでもが遠く感じてしまう程…。

ただ、やっぱり使い慣れたアプリケーションで開発したい言語もあります。
自分の場合は、特にFlashDevelopでActionScriptとか、DreamweaverでHTMLの更新作業とか。
このあたりのアプリケーション、メニューバーにある機能のキー設定はできても、基本的な(矢印キーとかの)キーバインドってできないんですよね。
プラグインを作れば、もしかするとできるのかもしれませんが、それぞれのAPIや対応した言語調べて書くってのはちょっと腰が引けます。

そこで、今まで何度か投げ出した、タイトルの「窓使いの憂鬱」の出番です。
Windowsの操作全体でも、アプリケーションごとでも、キーバインドを細かく設定できる常駐型のアプリケーションです。
設定ファイルを自分で作る際も、非常に簡単なシンタックスで記述できます。

インストールや簡単な使い方、導入時の注意事項などなどは上記の配布元や他の紹介サイトにお任せして、ココでは自分用のメモとして設定を書置きます。
メモなので、折を見て、端末の設定をこのエントリに反映させていきます(ぬかみそエントリ)。
(心残りVer.)とは、なるべくもとの操作に影響がないように…という、ちょっと後ろ向きな設定ですよー、という意味です。

include "109.mayu"

# プレフィックス系
keymap PrefixC-xGroup : Global
key M0-C = &WindowClose
key M0-S = C-S
key h = C-A

keymap Global
# まずは、特殊キーを用意。
# いつもは存在が希薄で、なおかつオイシイ位置にある
# [英数(CapsLock)]と、[無変換]を使う。
# ここで、イキナリCtrlやAltに割り当ててしまわないところがポイント。
mod mod0 = !英数
mod mod1 = !無変換

# カーソル移動系
key *S-*IC-M0-P = *S-↑
key *S-*IC-M0-N = *S-↓
key *S-*IC-M0-F = *S-→
key *S-*IC-M0-B = *S-←
key *S-M0-A = *S-Home
key *S-M0-E = *S-End
key M1-S-Comma = C-Home
key M1-S-FullStop = C-End

# テキスト編集系
key *IC-M0-H = BackSpace
key *IC-M0-D = Delete
key *IC-M0-M = Enter
key M0-Solidus = C-Z
key M0-W = C-X
key M1-W = C-C
key M0-Y = C-V
key M0-K = S-End C-X
key M0-S = C-F

# その他
key M0-V = PageDown
key M1-V = PageUp
key *変換 = *半角/全角
key M0-X = &Prefix(PrefixC-xGroup)


# Meadowは、もともとLinuxなキーバインドなので
# そのままキーが伝わるようにして、英数→Ctrl 無変換→Altに変更する。
window Meadow /Meadow\.exe/
mod ctrl += 英数
key *英数 = *LeftControl
mod alt += 無変換
key *無変換 = *LeftAlt
key *変換 = *半角/全角

はてな記法にも、さすがに.mayuのシンタックス・ハイライトはなかった><
他にも、「こんなの割り当てとくと便利だよー」というのがあれば、教えて下さい。

Schemeことはじめ

何がきっかけだったか、少し前にScheme 入門 1. Scheme 処理系のインストールを読んでいて、「Scheme を習うと筋が良くなる と言われています。」という言葉につられ、入門しました><

環境

状況

cygwin gauche meadow - Google 検索
この辺りを参考に開発・実行環境を用意。
ちなみに、パス通したりとかの設定がいろいろ省けるので、Meadowは/usr/local/meadowにインストールしました。

先に挙げたもうひとつの Scheme 入門で、そのまま勉強中です。今日で、8. 高階関数まで。
JavaScript再帰高階関数は扱うので、ここまではそれなりにスンナリ進めました。
実はSymbolやQuoteがまだちょっとシックリきてませんが><
Scheme再帰については、http://practical-scheme.net/index-j.htmlの、http://practical-scheme.net/docs/tailcall-j.htmlや、http://practical-scheme.net/docs/cont-j.htmlが面白いです。

あと、読み進めていて「えぇ!lispは、識別子の大文字・小文字を気にしないの!?」と面食らったのですが、Gaucheでは「デフォルトのモードでは、Gaucheのリーダとライタはシンボルの大文字小文字を区別します。」だそうです。

[追記]
2007年に策定されたSchemeの新仕様(R6RS)では、大文字・小文字の区別があるようです。
ただし、今までどおり区別しないモードを用意してもよい、とのことです。

id:SaitoAtsushiさんに教えていただきました。ありがとうございます。
参考:Revised^6 Report on the Algorithmic Language Scheme - Non-Normative Appendices -
[/追記]

Schemeの文法を覚え書き

変数・関数について、自分の目に馴染んでいるJavaScriptで「これは、これに当たるのかな?」というものを併記してみます。

変数定義
(define x 5)
var x = 5;
関数定義

無名関数

(lambda (x) (* x x))
function(x) { return x * x };

無名関数を変数に束縛

(define square (lambda (x) (* x x)))
var square = function(x) { return x * x };

上のシンタックス・シュガー
JavaScriptの方は全然違うけれど、「見た目的に」ということで。

(define (square x) (* x x))
function square(x) { return x * x }
関数呼び出し

束縛された関数を使う

(square 5)
square(5);

無名関数をその場で使う

((lambda (x) (* x x)) 5)
(function(x) { return x * x })(5);

所感

少しSchemeに触れてみて、「Scheme を習うと筋が良くなる」というのは、「問題の細分化と組立て方が旨くなる」ってことなのかな、と思いました。
他言語で言う「演算子」すらも関数で、それらを幾重にもネストしてコーディングしていくので、前もって処理の流れを考えるようになります。

逆に言うと、慣れの問題かもしれませんが「あ、あそこにこの処理を挟まなきゃ」みたいなことがしにくいです。
一先ずはガリゴリ書いて、カッコの嵐とEmacsの操作に慣れたいと思います。

防衛コードとアサーション

JavaScript用のアサーションを作ってみる - 檜山正幸のキマイラ飼育記 (はてなBlog)

ふむふむ。
防衛コード…あるある。
アサーション…こんな手があったか。

あぁ、やっぱり檜山さんのエントリはタメになりすぎです><
こういう、言語仕様とかとは別の、「プログラミングのキモ」みたいな所にメスを入れて書かれているものは、貴重な勉強材料です。

話題元についているコメントも大変勉強になります。
「過剰な防衛コード」が現れる時、内部(チームやプログラマー個人)での仕様やコーディングルールの策定、テスト等が疎かになっているケースが多い。
そこを踏まえて「防衛コードを書くな」なワケです。

ただ、しばらく考えているとナンダカ分からなくなって来ました。
話題元の例を見ると、「過剰な防衛コード」と呼ばれているものや、アサーションとして外部に追い出しているコードのほとんどが「型チェック」に費やされているような気がします。
これって、関数の入口や出口で型指定が出来ない言語特有の現象?
他の言語で「過剰な防衛コード」となり得るものってどんなものなのだろう?
こればっかりは、自分がその言語での開発に関わって、「ハッ、これは…!」と気づかないと本当の意味で理解は出来なさそうですね><

若干論点がズレますが…。

  • 確かに、JavaScriptのfunctionの引数、戻り値の型が問題になることは多い
  • サーバサイドの言語を咬ますのなら

ということで、こんな切り口を考えてみました。
実装は全然出来てません><

コメントで型指定
// foo.js
function sum(x/*:Number*/, y/*:Number*/)/*:Number*/ {
	return x + y;
}

記法はASのパクリです。

チェックしたいjsをCGIにパラメータとして渡す
<script src="assertJS.cgi?target=foo.js" type="text/javascript"></script>
こんな感じのレスポンスが帰ってくる
function sum(x, y) {
	// 実引数の型チェックのコード
	
	// 処理処理…

	// ついでに戻り値の型チェックのコード
	return x + y;
}
デメリット
  • 冗長。
  • JavaScriptらしくない…。
  • 頑張ってもコアクラスまでかなぁ。

・゚・(ノД`;)・゚・

Protocol Buffers - Googleが何か始めたみたいです。

メモです。
Protocol Buffers - Google 検索

まだ、ちら見しただけなので、イマイチ「何する人ぞ?」という感じですが、ふと檜山さんのとても素敵なデータ表現言語(やや難あり) - 檜山正幸のキマイラ飼育記 (はてなBlog)というエントリ(先方脚注のリンク先も要チェック)を思い出しました。
このあたりのソリューションだとしたら、ちょっと楽しみだなぁ。

4次元矢印

ActionScriptを触っていると、座標変換、色変換のあたりで何かと「マトリックス」や「行列」という単語に出会います。
自分は、恥ずかしながら数学の一分野(線形代数)であるということすら知らず、なんとなく雰囲気で使っていました。

一月程前、このままワケ分からないままというのもマズいなぁということで「amazon:プログラミングのための線形代数」を買ってきました。
…が、350ページくらいの書籍を未だ読み切ることが出来ません!それどころか、まだ100ページ前後をウロウロしている状態です。

この本、かなりの「スルメ本」です。少なくとも、自分にとっては。
何回か読み返すごとにイメージが湧いてくるようで、昼休みは大概これで潰れます><

で、何回か読み返した結果湧いてきた疑問で、なかなか解決しないところが2点。

まずベクトルについて、4次元以上の空間、座標、矢印ってどうイメージしたらいいの?という疑問。
成分の並びとして捉えた時の計算方法などは飲み込めたのですが、「この分野の主義は空間として捉える事」という記述が随所で見られるのでこの時点で躓くのはマズいかなと。

次に、急に単位ベクトルって出てきたけど、それって基底ベクトルと違うものなの?という疑問。
ベクトルに行列を施すあたりで、「行列の第1列目はe1 = (1,0,0,..)Tの行き先」という表現が出てくる(Tは転置)のですが、この(1,0,0,...)Tというのが分からないのです。
これは、基底ベクトルを再帰的に座標で表現した時の話なのか、それとも基底がたまたま直交(?)だった時だけ通じる話なのか…。

と、こんな感じで、三歩進んで二歩退がりながら読んでます><
学生(高校)時分に幾らでも学べたのに、本分を全うしていなかったことが本当に悔やまれます…。

文とハッシュ生成・探索のパフォーマンス

ふと見かけた、さまざまなフォーマットで日時を表示させるためのJavaScriptの記法いろいろ | IDEA*IDEAのエントリについてです。
ここで話題になっている、Dateオブジェクトをある書式に変換したいというのは、ままあるニーズです。
案件毎にフォーマットも違うので、毎回ガリゴリ書いちゃうんですよね><

確かによくまとまっているのですが、少し気になったことがあるので書き置きます。
テーマは残念な話。 ―配列への循環アクセス 2― - 外付Web海馬でも述べた、「スマートな書き方とパフォーマンス」のようなところです。

話題元の関数がよくまとまっている要因の一つは、英語表記の月名を配列から取得していることだと思います。
ではさっそく、見てみましょう。簡単のため、引数の型チェック等は省きます。

まずは、プログラミングの入門書っぽく。

function getMonthString1(monthIndex) {
	switch (monthIndex) {
		case 0: return 'January'; break;
		case 1: return 'February'; break;
		case 2: return 'March'; break;
		case 3: return 'April'; break;
		case 4: return 'May'; break;
		case 5: return 'June'; break;
		case 6: return 'July'; break;
		case 7: return 'August'; break;
		case 8: return 'September'; break;
		case 9: return 'October'; break;
		case 10: return 'November'; break;
		case 11: return 'December'; break;
	}
}

うーん、泥臭い><

次に、話題元っぽく。

function getMonthString2(monthIndex) {
	var monthString = [
		'January', 'February', 'March',
		'April', 'May', 'June',
		'July', 'August', 'September',
		'October', 'November', 'December'
	];
	return monthString[monthIndex];
}

うーん、スマート!

でもちょっと待って。

ここで、それぞれ関数の速度を計ってみましょ。

ストップウォッチを用意。
function getTheFuncOut(func, args, t) {
	args = args[0] ? args : [args];
	var start, end;
	start = new Date();
	for (var i=0, imax=t||10000; i<imax; i++) {
		func.apply(null, args);
	}
	end = new Date();
	return end - start;
}
計ってみる。
console.log(getMonthString1(6));	// July
console.log(getTheFuncOut(getMonthString1, 6) + 'ms');	// 62ms
console.log(getMonthString2(6));	// July
console.log(getTheFuncOut(getMonthString2, 6) + 'ms');	// 563ms
おっと、すごい差が出ました。

10000回呼ぶことは無いにしても、1ページにつき複数回呼ばれる可能性の高い関数でこの差はちょっと見逃せません。差の原因は、ハッシュの生成とそれの探索にかかるコストです。

ただ、話題元でも
ちょっとだけ使いたいときは自分で書きたいですよね。
とあるように、このスマートさは捨てがたい…。
そこで、次の様な書き方はどうでしょか。

JavaScriptっぽく

var getMonthString3 = new function() {
	var monthString = [
		'January', 'February', 'March',
		'April', 'May', 'June',
		'July', 'August', 'September',
		'October', 'November', 'December'
	];
	return function(monthIndex) {
		return monthString[monthIndex];
	}
};

console.log(getMonthString3(6));	// July
console.log(getTheFuncOut(getMonthString3, 6) + 'ms');	// 78ms

JSっぽいというかクロージャってやつですね。
メモリは食いますが、ハッシュの生成を一回に収めています。
どうしても泥臭いのよりは遅いですが、スマートさとパフォーマンスのバランスは良い感じじゃないでしょうか。

関数生成関数にも名前を付けて、引数に'jp'とか'en'とか渡して、みたいにすると汎用的に使えるかも知れません。応用して、「Dateオブジェクトをある書式に変換」を、'%year年%month月%date日(%day)'みたいな引数を元に関数を生成するなんてのも面白いですね。

おや?

ストップウォッチも結局毎回ガリゴリ書いちゃってますね><(前回)

初心者用の言語としてのJavaScript

またもや間が空き、大幅に時期を逸してしまいましたが、私がJavaScriptを初心者用の言語として選んだわけについて触れて見ます。

型について

前回のエントリで比較した変数・関数定義だけを取ってみても、JavaScriptは(今最も普及しているバージョンでは)かなりユルい言語です。
代入する値の型が何であろうが変数宣言はvarのみですし、戻り値の型、仮引数の型が何であろうが関数宣言はfunctionのみです。
初学者にとってのメリットは、覚えることが少なくて済むという点、デメリットは多言語に移った際に面倒に感じてしまう点でしょうか。

開発・実行環境などについて

また、多くの方が言及されているように、インタプリタ型であるという事や、最初から環境が整っているという事は、とっつきやすいという点で大きなメリットだと思います。

もう一つよく議論のネタに上がるのは、「プロトタイプベースのオブジェクト指向言語」であるということでしょうか。
確かにJava等、実務でよく使われる言語がクラスベースであることが多い今、毛色の違うJavaScriptから学ぶのは少々遠回りな気もします。

しかし、「猫も杓子もオブジェクト」ということが分かってしまえば「プロトタイプを使ったプロパティ探索」は非常に分かり易い仕組みだと思います。
そして、ここでしっかりと「オブジェクト指向でプログラミングをする」ということに慣れておけば、他言語を学ぶ際にも大きな土台となるのではないでしょうか。

この点について自分は、id:hiyamaさんのプログラマのためのJavaScriptを拝見し、実際に動かしてみることで理解しました。
「prototypeワケワカンナイ」な方で、この記事を読まれたことのない方は是非読んでみて下さい。超オススメです><

で、結局どうなの?

結局、JavaScriptは初心者用言語としては最適だと思います。
開発・実行が簡単という点が何よりの強みです。

また、学習が進むと型についての弱点も自前で型チェックを行うことである程度対処出来る部分もありますし、そうすることで理解も深まりますね。
他の弱点についても同様です。
そうして学習するうちに上に挙げたようなデメリットを実感出来たらシメたもの、他の言語に浮気すればよいのです。

因みに、ラ・マン候補には「ECMA Sctipt友達」で、「成果物をそのままWebで公開できる」ということで、AS3.0(Flex)をオススメします。

さらに、JavaScript自体が今ではWeb技術の核を成す言語になっており、(X)HTML、CSSと併せて学習すれば、そのまま業務に利用出来る立派なプログラミング言語だと思います。
学習して損はありません(キッパリ)。

おまけ

自分が「prototypeワケワカンナイ」頃にJavaScript でソートアルゴリズムを可視化に触発されて作った、3種類のソートが進む様子を点で表すJavaScriptです。
Sort Demo

説明を書き加える際に自分で書いたJavaScriptを見渡してみました。
それぞれのソート用の関数はsetIntervalを使った描画を含んでいるため、このままでは全く再利用性がありません。
にもかかわらず態々Array.prototypeにメソッド定義していたり、破壊・非破壊のフラグがあったり、ソート済みのArrayを返していたり…。
一体何がしたかったのでしょうか…。ま、見た目は面白いと思います><