トップ 最新 追記

じじぃの日記、ツッコミ可

Twitter: @jijixi_org
Xbox Live: jijixi

初心者が書いた OCaml 入門
Spotlight tips サイト内リンク集
1970|01|02|
2003|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|11|
2011|05|
2012|01|

2007-08-01 [長年日記]

% [clip][Erlang][Python] Erlang vs. Stackless python: a first benchmark (Muharem Hrnjadovic)

via programming reddit.

Erlang book のリングベンチマークを Erlang と Stackless Python でやってみたという話。 最初やってみたら、Stackless の方が速くて「あれー?」って感じだったけど、これは Erlang の I/O ライブラリが超遅いせいで、I/O が絡まないようなコードにしてみたら、やっぱり Erlang の方が速かったよ、みたいな流れか。

んで、Erlang はたしかにすごいんだけど、Stackless もあなどれないなという感じで、

Python は、これからのメニーコア時代に向けて大きな可能性を持っている。 Python コミュニティで Stackless が "unloved stepchild" (愛されない継子?「いらない子」みたいなニュアンスだろうか) のように扱われているのはあんまりだ。

……というような結論。

個人的には Stackless のマイクロスレッドライブラリは、あんまり使いやすいようには思えないんで、もう少し気軽に使えるような作りにしてくれないと、メニーコア時代の言語にはなれないような気もする。 まあ、ネイティブスレッドにこだわってる言語 (ぶっちゃけ本家 Python のことだが) に比べれば、遥かに可能性があるとは思うけど。 この辺、Python3000 ではどうなるんだろうね。(調べてないので知らない)

% [clip] 猫怖い (にゃんねる)

まんじゅう怖い。

% [Python][Erlang] Stackless Python の tasklet (マイクロスレッド) はプリエンプティブではない

なんとなくネタにした関係上、スイッチが入っちゃってついつい Stackless Python をいじっていたりして。 「あんまり使いやすいようには思えない」とか偉そうなこと書いたものの、実のところ Stackless のマニュアルを斜め読みしただけの知識しか無いので、まあ、もう少しくらいはいじっとくか、とね。

で、表題の件。 組み込みのスケジューラではタイムスケジューリングはされず、tasklet を無理矢理止めるような方法も無いようなので、独自にそういうスケジューラを作るのも難しそう。 なので、

In [1]: from stackless import *

In [2]: import sys

In [3]: tasklet(lambda: raw_input())()
Out[3]: <stackless.tasklet object at 0x13f46f0>

In [4]: tasklet(lambda: sys.stdout.write('hoge'))().insert()
Out[4]: <stackless.tasklet object at 0x13f4730>

In [5]: stackless.run()
fuga
hoge

てな感じで (raw_input によるブロックが解除されないと hoge が表示されない)、ブロックする IO を別のスレッドで……みたいな用途には使えない。 そういうのは結局システムスレッドを使う他無い。

ちなみに

tasklet(lambda x: x)(42)

は、

tasklet().bind(lambda x: x).setup(42)

と同じ。 insert メソッドはスケジューラキューの最後に追加するという意味ね。

Erlang だと、こういうのは簡単で、

1> spawn(fun() -> timer:sleep(2000), io:format("hoge\n") end), io:get_line('').
hoge
fuga
"fuga\n"

諸般の事情で io:get_line はシェルプロセスで動かしてるけど、ともかくブロックしてる間にちゃんと hoge が表示されているのはわかると思う。

Stackless でも、システムスレッドでプールを作って、ブロックしそうな tasklet はそっちに逃がすようにすれば対処は可能なはずで、実際 Stackless のサイトではそんな感じのサンプルコードなんかも紹介されていた。 まあ、これくらいの機能はデフォルトで組み込んでくれても良いんじゃないのかなーという気もするが。

ところで、Erlang でもシステムコールレベルでブロックする処理がたくさんある場合には、どうしてもツラくなるんだけど、そういう場合は VM オプションの +A (async thread pool) を使えば回避できるそうな。→参考リンク:Erlangの+Aオプション(みかログ)

% [clip][Python] ぱ、ぱいそんにだってcollectionsくらいあるんだからねッ! (神様なんて信じない僕らのために)

はい、わしも 『collections -- 高性能なコンテナ・データ型』とか書いてあるのを見て、ドキドキしながらページを開いたらがっかりした口です(笑

deque しか無いってのもがっかりだけど、deque の説明で、

list オブジェクトでも同様の操作を実現できますが、

などと言っておきながら、インターフェイスを一致させようとかいう気が全く無さげなのに絶望した(苦笑)。 どうせこういう構成なら、append や pop の別名で appendright とか popright とかも用意しろと言いたい。 つーか、なんで append_left じゃなく appendleft なんだ。キモい。 まあ、関数名やモジュール名にアンダースコアを入れないのは、Python 全体に渡るキモさだが。 しかも、それで統一されてるわけでもなくて、キャメルケースのクラスなんかもあれば、アンダースコアが入った関数名とかもあって、こう、じわじわと拡張されてきた歴史を感じつつも、ぐったりすることしきり。


2007-08-02 [長年日記]

% [雑談] 暑い

というか、蒸し暑い。 大雨が降ったりしてるけど、全然涼しくない。 風がぬるい。

……これが日本の夏というやつなのか。 まあ、このところこの辺は雨が少なかったから、農家にとっては恵みの雨になるだろうけど、そうでない人としては、この蒸し蒸し感は勘弁願いたい。 ちなみに室温が約 30 ℃で、湿度が 65% ほど。

北海道の夏ってのはさあ、もっとカラっとしてるもんだし、雨が降ればぐっと気温は下がるもんであって、こんなのはもう北海道じゃないと思うんだ。 だるー……


2007-08-03 [長年日記]

% [雑談][Erlang] Comet ってのが何なのか知らなかったので調べてみた

最近よく目にするものの、Comet ってなんじゃらほい?ということで。 とりあえず ja.wikipedia とかチェック。

これ考えた人、頭やわらかいなー。 まさにコロンブスの卵。 HTTP 考えた人とかびっくりしてんじゃない?

「リクエストを受けても、サーバ側でイベントが起こるまでレスポンスを返しません」

とか、「ちょwwwおまwww」って感じだよね。

しかしまあ、あれだね、わしもきっと元々 Comet の存在を知ってたら、Erlang でサーバ書いてみようと思ったかもしれないくらい Erlang 向きなお題だ。→参考リンク『みかログ: ErlangでComet』『letter: Erlang で Comet

まあ、素朴な実装で良いなら、クロージャが使える言語使えばそれほど手間無く書けそうではある。 要するにリクエストが来たら、「レスポンスを返す」代わりに「レスポンスを返すクロージャをどっかに保存」するようにして、イベントが起きたらその溜めといたクロージャを一気に実行すれば良いわけでしょ。 んー、クロージャが無くても環境を保存しとけば同じか。 どっちにしろ、やってることはクロージャによる超軽量並行プロセスに近い。

や、だから何だって言われても、別に何も。 ちょっぴり Stackless Python で書いてみようかな…とか思ったけど、思っただけ。


2007-08-04 [長年日記]

% [雑談] 仕事決まりました

おかげさまで、なんとか収入を確保できそうなことになりました。 関係各位にはお世話になっております。

そんなわけで、お仕事募集はとりあえず打ち切りです。 ただし、単発の案件はスケジュールが許せばお受けできますので、ご相談ください。

% [Python] Parallel Python

via programming reddit.

分散環境を簡単に構築するためのライブラリ……だと思う。 正直、'pp' なんつーモジュール名を使う傲慢さに苦笑を禁じ得ないが。

とりあえず、サンプルコードを見た感じ、Erlang の rpc:pmap みたいな使い方をするっぽい。 サーバにジョブを投げると、適当なワーカに処理が渡されて、呼び出し元には結果を取り出すためのクロージャが戻ってくるので、あとでそれを使って結果を得るという形。

んで、ちょっと試してみようと思って IPython で動かそうとしたんだけど…

In [1]: import pp

In [2]: server = pp.Server(5, ppservers=())

In [3]: server
Out[3]: <pp.Server instance at 0x13e1850>

In [4]: def f(x):
   ...:     return x + 1
   ...: 

In [5]: server.submit(f, (10,))
---------------------------------------------------------------------------
<type 'exceptions.IOError'>               Traceback (most recent call last)

/Users/jijixi/<ipython console> in <module>()

/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/pp.py
in submit(self, func, args, depfuncs, modules, callback, callbackargs, group, globals)

...(ソースコードのダンプなので略)

<type 'exceptions.IOError'>: could not get source code

ショボン。 ソースを拾い読みしてみると、どうも pp.Server は指定した分の Python プロセスを立ち上げて、それをワーカプールとしてジョブを割り振ってるみたいだけど、その割り振るときに使用する関数 (上の例で言えば f のこと) のソースを inspect モジュールを使って取得して、それをワーカプロセスに渡して実行させてるみたい。 んで、対話環境でやると、そのソースを取得するときに失敗するということのようだ。 逆に言うと、ソースが無い関数は実行できないみたいで、例えば↓みたいに組み込み関数を渡しても、

In [8]: server.submit(abs, (10,))
---------------------------------------------------------------------------
<type 'exceptions.TypeError'>             Traceback (most recent call last)

...(略)

<type 'exceptions.TypeError'>:
 arg is not a module, class, method, function, traceback, frame, or code object

…てなことになる。 しかもサンプルを見る限りでは、使う関数が他の関数やモジュールに依存してる場合 (sum_primes.py の例で行けば、sum_primes 関数は isprime 関数や math モジュールに依存している) submit のときにそれらも指定してやらないといけない。

なんか微妙。

そもそもソースコードを送って実行させるってのが微妙な気がするけど、どうなんだろうね、これ。 Erlang みたいに、あらかじめワーカプロセスに必要なモジュールを読み込ませておいたりとかできないのかな。

ともあれ、微妙さは感じるものの、比較的簡単に分散環境を作れそうではあるので、おもしろいことはおもしろいかと。

% [clip] なにやっとるん?あんたのお母ちゃんよ。 (Web屋のネタ帳)

迷作キタコレwww

% [雑談] ぼてまよが密かにおもしろい件

当初、オープニングだけ見てスルー決定してたんだけど、ふとしたきっかけで見てみたら超おもしろい。 いろいろシュールすぎw

とりあえず、パッと見で敬遠してる人も一度は見てみるべき。

本日のツッコミ(全3件) [ツッコミを入れる]

% きむら(K) [おお、就職(って云うのかこういう場合も?)おめでとうございます。 ぽては、「ふにふに」と「しゃー」にやられたとか?w]

% jijixi [どーもです。 > ぽて 見た目、謎の人型生物ですけど、行動が猫っぽいですね、あれは。 あと、ぐちょ子が斬ったものを..]

% きむら(K) [あーネコっぽいってのはそうですねえ。 たしかにガムテによる修復は良いですね、はいw]


2007-08-05 [長年日記]

% [雑談] えー?

xtal をクリスタルって普通に読める人は、普通にいっぱいいますよね?

…とか言ってみるテスト。 参考1参考2


2007-08-06 [長年日記]

% [clip][C++] 年を取るとC++が難しい (なつたん)

やばい、わしも同じようなことやりそう(笑

わしは『組み込みプログラマ』というほどそっち方面じゃないけど、ちゃんと書いたことがある C のコードは大体そっち方面なんで、malloc とかほとんど使ったことない罠。

% [clip] CVSユーザのためのSubversionガイド (wakatono の日記)

なんか今さらだけど、中学生になるために、小学生のための中学校ガイドを探してみたので。 ぶっちゃけ、svn のサブコマンドで使ったことあるのは checkout と update のみ。

ところで cvs で一番つらいのは、csv が絡んだものを作るときだよね (なんだってー!?)。 何度 zsh に、

% csv up
zsh: correct 'csv' to 'cvs' [nyae]?

と確認されたかわかんねーよ。 もしくは、何度ソースに CVS と書いて、そんなモジュール無ぇよと怒られたかわかんないよ...orz

% [clip][game] 噂: TGS 2007のセガ出展ゲームリストが掲載!Xbox 360でシェンムーが?! (Game*Spark)

ちょwww それほんとだったら箱○始まるわ、個人的に。

% [clip] Subversion によるバージョン管理

小学生のための中学校ガイドその2

どうでも良いけど、Safari3 でこのページ見たときのタブのタイトルが『によるバージョン管理』になってて謎。 なぜ先頭が省略される……

Subversion はブランチとタグを通常のディレクトリのように扱うので、 いつもプロジェクトのtrunk (http://svn.example.com/repos/calc/trunk/) をチェックアウトし、プロジェクト自身(http://svn.example.com/repos/calc/) をチェックアウトしないように注意してください。プロジェクト自身をチェック アウトすると、作業コピーはすべてのブランチとタグを含むプロジェクト全体 になってしまいます。

これは間違いそうだから注意しよう。

% [Python] itertools 探検

無限イテレータ作成

count([n])
n (省略時は 0) から始まる無限数列
In [1]: import itertools as it

In [2]: ct = it.count()

In [3]: for _ in xrange(3):
   ...:     print ct.next()
   ...: 
0
1
2
cycle(iterable)
一つのイテレータを無限に繰り返すイテレータを作成
In [4]: cy = it.cycle(xrange(3))

In [5]: for _ in xrange(10):
   ...:     print cy.next()
   ...: 
0
1
2
0
1
2
0
1
2
0
repeat(object [, times])
times の回数分 (省略時は無限に) object を返すイテレータを作成
In [6]: rep = it.repeat(1, 3)

In [7]: for i in rep:
   ...:     print i
   ...: 
1
1
1

リストを扱うような操作

izip(*iterable)
イテレータを返す zip
In [12]: iz = it.izip([1,2,3],[4,5,6],[7,8,9])

In [13]: for _ in xrange(3):
   ....:     print iz.next()
   ....: 
(1, 4, 7)
(2, 5, 8)
(3, 6, 9)
ifilter(predicate, iterable)
イテレータを返す filter
In [16]: ifilt = it.ifilter(lambda x: x < 3, xrange(10))

In [17]: for _ in xrange(3):
   ....:     print ifilt.next()
   ....: 
0
1
2
ifilterfalse(predicate, iterable)
ifilter の predicate が逆向きバージョン

例は、いらんでしょ。

islice(iterable, [start,] stop [, step])
イテレータを返す slice (ただし、start, stop, step に負に値は使えない)
In [18]: isl = it.islice(it.count(), 3)

In [19]: for i in isl:
   ....:     print i
   ....: 
0
1
2

Haskell における take の代わりに使えそう。

imap(function, *iterable)
イテレータを返す map

In [20]: im = it.imap(lambda x: x * 2, it.count())

In [21]: for _ in xrange(3):
   ....:     print im.next()
   ....: 
0
2
4
starmap(function, iterable)
ネストした iterable に対する imap
In [26]: sm = it.starmap(lambda *x: x[0], it.izip(xrange(3),xrange(3,6)))

In [27]: for i in sm:
   ....:     print i
   ....: 
0
1
2

いまいち存在意義がわからん。

tee(iterable [, n=2])
iterable を n 個に分割 (というかコピーに近い)
In [39]: i = (x for x in xrange(10))

In [40]: i.next()
Out[40]: 0

In [41]: t = it.tee(i)

In [42]: list(t[0])
Out[42]: [1, 2, 3, 4, 5, 6, 7, 8, 9]

In [43]: list(t[1])
Out[43]: [1, 2, 3, 4, 5, 6, 7, 8, 9]

生成時じゃなく、実行途中の状態で複製されるのがポイントか。 説明にも書いてあるけど、こんな↓ことするとショボン。

In [44]: i = (x for x in xrange(10))

In [45]: t = it.tee(i)

In [46]: i.close()

In [47]: t[0].next()
---------------------------------------------------------------------------
<type 'exceptions.StopIteration'>         Traceback (most recent call last)
chain(*iterable)
複数のイテレータを繋いで一つにする
In [50]: ch = it.chain(xrange(2),xrange(3),xrange(4))

In [51]: ch.next()
Out[51]: 0

In [52]: for i in ch:
   ....:     print i
   ....: 
1
0
1
2
0
1
2
3
takewhile(predicate, iterable)
predicate が偽になるまで iterable から take
In [53]: tw = it.takewhile(lambda x: x < 3, it.count())

In [54]: for i in tw:
   ....:     print i
   ....: 
0
1
2
dropwhile(predicate, iterable)
predicate が偽になるまで iterable から drop
In [55]: dw = it.dropwhile(lambda x: x < 3, xrange(5))

In [56]: for i in dw:
   ....:     print i
   ....: 
3
4
groupby(iterable [, key])
key (要素からキーになる値を返す関数) が同じ値を返す要素を各イテレータにグループ化して返す

使い方がよくわからん。 こうですか?わかりません。

In [76]: gb = it.groupby(xrange(10), lambda x: x % 2 == 0)

In [77]: for k, g in gb:
   ....:     print k, list(g)
   ....: 
True [0]
False [1]
True [2]
False [3]
True [4]
False [5]
True [6]
False [7]
True [8]
False [9]

こうじゃなく、先に同じ key でソートしとかにゃいかんらしい。

In [78]: kf = lambda x: x % 2 == 0

In [79]: gb = it.groupby(sorted(xrange(10),key=kf), kf)

In [80]: for k,g in gb:
   ....:     print k, list(g)
   ....: 
False [1, 3, 5, 7, 9]
True [0, 2, 4, 6, 8]

大変微妙なことに、グループ化する際に前にグループ化したものは消費されてしまうので…

In [89]: gb = it.groupby(sorted(xrange(10),key=kf), kf)

In [90]: _,g1 = gb.next()                              

In [91]: _,g2 = gb.next()                              

In [92]: g1.next()
---------------------------------------------------------------------------
<type 'exceptions.StopIteration'>         Traceback (most recent call last)

g1 の中身無ぇーーー……ということに。 なので、後で必要なときは list() とか使って保存しておけということの模様。

% [Python] itertools.islice がイマイチ take の代わりにならなかった件

しかたないと言えばしかたない気もするけど、できれば何とかして欲しかったと思わなくもない。

In [1]: from itertools import *

In [2]: inf = count()

In [3]: took1 = islice(inf, 5)

In [4]: took2 = islice(inf, 5)

In [5]: list(took2)
Out[5]: [0, 1, 2, 3, 4]

ここまでは良さそうに見えるんだけど…

In [6]: list(took1)
Out[6]: [5, 6, 7, 8, 9]

がくっ...orz

そして当然…

In [7]: for _ in xrange(5):
   ...:     print inf.next()
   ...: 
10
11
12
13
14

こうなるんだなー。しょぼ〜ん。 まあ、そもそもイテレータ (もしくはジェネレータ) を Haskell のリストと同じようなものと考えるのが良くないんだろうけど。

こういうことやりたい時は、元リスト (上の例で行けば inf) には手を付けずに tee で必要な分だけ増やすのが良いのかな。 それでも結局 tee で使った方を進めちゃうと元のも進んじゃうんだけど。

やっぱ、同じイテレータが欲しいなら、いちいち最初から作るしか無いのかもね。 要は、こう↓しろと。

In [15]: took1 = islice(count(0),5)

In [16]: took2 = islice(count(0),5)

In [17]: list(took1)
Out[17]: [0, 1, 2, 3, 4]

In [18]: list(took2)
Out[18]: [0, 1, 2, 3, 4]

% [clip][雑談] 人体からのエネルギーで、エネルギー問題は解決! (鍋あり谷あり)

ワロタ。 人間始まったなw

% [雑談] プラス電子と言えば、マイナスイオンもかなりアレゲな言葉だったよなー

…と思ったら、なんか Wikipedia に登録されてるわ(笑

しかし、なんでこんな中学生レベルでも見抜ける『とんでも』を信じちゃう人がいるんだろうねぇ……。 それでもまあ、マイナスイオンの場合は、陰イオンって習ってると何となく同じものに見えちゃうのもわからなくはない。 でも、さすがにプラス電子は無いだろ。

そういや、アレはどうなったかな、悪い電子を監視してウイルス防ぐってやつ。 壮大な釣りじゃないかと思ってたんだけど。

本日のツッコミ(全8件) [ツッコミを入れる]

Before...

% jijixi [> 自分で定義したジェネレータは何故かコピーできませんでしたorz ありゃま、微妙に残念ですね。]

% morchin [自分のブログにも書いたのですが、itertools.teeでユーザ定義のジェネレータを複製できました:-) copy..]

% jijixi [見ました〜 tee にしろ islice にしろ元になるイテレータ(ジェネレータ)が完全な支配下に無い状況では使いに..]


2007-08-07 [長年日記]

% [雑談] 何人かの人のエントリが LL 魂じゃなく LL 妖精さん (ただし寸足らず) になっている件

英語ではない言語 (なんだかよく知らない) には sprit という単語が存在するようだけど、それが spirit と同じ意味なのか、あるいは split と同じなのか、はたまた全然関係無いのかは不明。

ちなみに、ここで言う『妖精さん』は sprite (スプライト)。 昔のゲーム機で激しくチラついたりするアレ。

% [雑談] 絶賛夏バテ中

食欲が無い〜〜...orz

なんか今年の夏は湿度が高くて、北海道っぽくないのが敗因かなー。 精のつくもんでも食わんと……と思いつつ、ついつい素麺とか茹でちゃう意思の弱さが悲しい。 せめてもの補填にと、つゆに生卵落として食ったりしてるけど、焼け石に水だよねぇ……

% [雑談] 今日の創作料理『納豆ラーメン』

創作というか、うろ覚え料理。 どっかで「炒めた挽肉の代わりに炒めた納豆を入れるラーメンがある」と聞いたことがあって、それを適当に再現してみますた。 たったそれだけの情報で!?

とりあえず納豆を炒めるって、どうすりゃええねん……と思いつつも、ごま油を敷いたフライパンでてけとーにわしゃわしゃ。 ちょwww においヤバスwww

せっかくだから納豆についてきたタレも突っ込んどく (良いのか?)。 ラーメンはもちろんインスタントで (それしか無いし) 屋台十八番しょうゆ味。 できあがったラーメンに、納豆を投入して完成。 簡単すぎます。

…………んで、結果。

汁が五割増しで旨くなった気分。結構良いお出汁が出た模様。 しかし、底に沈んだ豆部分をどうすりゃ良いのかわからん。 なんかもったいないので食ってみたが、う・ま・く・な・い...orz

結論。 納豆炒めるときのにおいに耐える覚悟と、炒めた納豆は出汁のためだけに使ってガラは捨てる覚悟があれば、試してみるのも一興。 あ、あと納豆炒めのにおいはわりとこもるので、家族から大不評w

そんな感じで、食欲不振をネタと勢いで乗り切ろうシリーズその1完。 続きません。

% [vim] snippetsEmu.vim というのをお薦めされたので入れてみた

Mac ユーザの間でわりと有名なエディタ TextMate の Snippets という機能を真似たものらしい。 さっそく、vim online からゲットしてインストール。 インストール方法はググればいくらでも見付かるはずなので、わざわざ書かない。

で、使う………うは、なんか新しい世界が。 TextMate って何であんなに人気あるんだろうと思ってたけど、こんな機能が付いてやがったのか。 ずるいぞ。(何がだ?)

使い方↓ (例は Ruby)

 1 class
        ^

^ の位置にカーソルがある。 このように挿入モードで class まで書いた時点で TAB キーを押す (もちろん Ctrl+I でもオッケ) と…

 1 class <{className}>
                   ^
 2    <{}>
 3 end
 4 <{}>

こんな風になる (1 行目の下の行はわしが追加してるよ)。 このとき、実際には className のところは反転している……というかセレクトモード (ビジュアルモードの仲間) で選択されている状態。 セレクトモードって何じゃい?って人は VIM 完全バイブルとか買って読むと吉 (ここでアサマシ貼る…と行きたいところだけど無し)。

そんで、これはビジュアルモードで選択したのとは違って挿入モードの状態なので、そのままクラス名を入力する。

 1 class <{Hoge}>
               ^
 2    <{}>
 3 end
 4 <{}>

で、真っ当な vi 使いなら、ここでつい ESC を叩いてしまうところだが、そこをグッとがまんして TAB を押す。 ……と、こう↓なる。

 1 class Hoge
 2    
      ^
 3 end
 4 <{}>

カーソルの桁位置は shiftwidth の設定によって違うだろうけど、ともかく、<{}> と表示されていたところにカーソルが移るわけだね。 そしたら、このまままた中身を書いて……

 1 class Hoge
 2    p 'hoge'
              ^
 3 end
 4 <{}>

やっぱり ESC ではなく TAB を押す。

 1 class Hoge
 2    p 'hoge'
 3 end
 4 
   ^

完成。って言うか、class の中身に p は無えだろ(笑

ともかく、こういう感じで、定型的な雛形を用意してくれるという機能みたいだね。 んで、この機能が本領を発揮するのは、むしろブロック付きメソッドを呼ぶような時なんかで、

 1 ary.each
           ^

この状態で TAB を押すと、

 1 ary.each { |<{element}>| <{element}>.<{}> }
                       ^
 2 <{}>

こうなる。 そんでもって、element のところを適当に書いて TAB を押すと、

 1 ary.each { |hoge| hoge. }
                          ^
 2 <{}>

こう。 element という同じ仮識別子が付いてたところが、一発で置換される。

このプラグインの各ファイルは ~/.vim/after/ftplugin にインストールされているので覗いてみると、なんか OCaml とかまであって、ちょっと笑う。 せっかくだから、どんなのが登録されてるか見てみたら、かなり微妙なラインナップで苦笑。 List に TAB で、

 1 List.rev_map <{:D('(fun x -> )')}> <{lst}><{}>
                                          ^

とか、どんだけ(苦笑)。 つーか、関数部分のところにカーソル動かす方法がわからん。 ともあれ、この Snippet パターンを追加するのはそれほど難しくもなさそうなんで、足りない分は自分でいろいろやれば良いんだろう。

Python だと classi でこんな↓の出た。

 1 class <{ClassName}> (<{object}>):
                   ^
 2 
 3     def __init__(self<{args}>):
 4         <{args}>
 5 
 6         <{}>

% [clip] rm -rf * (programming reddit)

写真への直リンクで登録されてるので、リンクは reddit にしてある。 後で見ようと思って裏のタブに開いておいたのを、忘れた頃に見たら何事かと思ったよ(苦笑

日本もこういうフリーダムな (謎) ナンバーが許されるようになれば良いのに。

本日のツッコミ(全1件) [ツッコミを入れる]

% TrackBack [http://blog.blueblack.net/item_133 ナレッジエース Vimを使ったRuby On ..]


2007-08-08 [長年日記]

% [雑談] 昨日の夜に設定したパスワードが、今朝すでに思い出せない

痴呆症始まったか...orz

% [独り言] 環境構築に追われて、なかなか本来の作業に入っていけない

まあ、土台固めは大事だし、あせってもしかたがないか……

% [FreeBSD] sudo の仕様変更でひどい目にあった件

以前の sudo コマンドは、基本的に環境変数は全て引き継ぐ仕様だったんだけど、なんかそれがセキュリティ的に危ないとかで、最近のバージョンでは -E オプションを付けないと (かつ、そのための権限を与えられていないと) ごく一部のものを除いて環境変数が引き継がれないようになっている。

そんでまあ、それはそれで良いんだけども。

今、うちにある FreeBSD マシンでは、ports ツリーを別のマシンから NFS でマウントしている。 ぶっちゃけて言うと、別のマシンというのは Mac OS X なんだけど、こいつの NFS サーバはバージョンが古いのかロックがサポートされてなかったりして、素直に ports ツリー内部でビルドすると様々な port でビルドエラーになって悲しいわけ。 で、それを回避するために、WRKDIRPREFIX という環境変数を設定して、ビルドするときに使われるワーキングディレクトリをローカルな場所に設定していた。 (速度の問題を考えても、こうした方が良いと思う)

そんな感じで、まあ、わかると思うけど、この二つの事柄が組み合わさった結果、最近になってなぜか port のビルドに失敗するものがあるなーという話になるわけだ。 というか、この二つの事柄が頭の中でなかなか結びつかなくて、すごく悩んだ。

ともあれ、そういうわけで、visudo で sudores のエントリに SETENV: という記述を加えて (加えるのは NOPASSWD: とかと同じ位置)、portupgrade などを実行するときは sudo -E を使うようにすることで解決した。 あー、無駄に疲れた。


2007-08-09 [長年日記]

% [Mac] あー、薄い iMac いーなー

欲しーなー。 なんかうちのヤツの半分くらいの薄さに見えるなー。 や、たぶん、はじっこの部分は実際それくらいな気がする。

まー、買う金は無いので、こいつは置いといて。

手が出そうな範囲で、今一番心惹かれてるのは、やっぱワイヤレスキーボードだーね。 たぶん、MacBook のキーボードと同じようなタッチなんだと思うけど、あれはあれで慣れればわりと良い感じなんじゃないかと思ってたりする。 あとまあ、Mac 用の特殊キーが使えるコンパクトキーボードが欲しかったんだよね、ずっと前から。

…つーか、特別ワイヤレスである必要は無いから、もっと安くコンパクト版を作ってくれよと言いたいが。 貧乏性だから、電池式とかってすごく気になるんだよなー(苦笑

% [Rails] あれ〜? ActionMailer って、素の状態だと Mime encode しないのか?

ん〜〜?? デフォルトだと文字コードは UTF-8 で、QuotedPrintable でエンコードして送るんだと思い込んでたけど、なんかエンコードせずに 8 bit のまま送るっぽい?

ちょっと素の状態のときに、どこでエンコードしてるのか知りたくなって一生懸命ソースを追ったんだけど、いくら探してもその場所が見付からないんだよなー。 今となっては、とっととテスト環境作って、実際に試してみた方が早かったという気がする。 や、すぐ見付かると思ってたんだよ...orz

そもそも、どうしてそういう風に思い込んでたんだっけ? どっかで読んだ何かの記事に、そんな事が書いてあったんだったかな。

しかし、QuotedPrintable もたいがいだけど、8 bit で送るのもたいがいだなあ。 まあ、ascii の範囲ならぶっちゃけ何にも関係無い話だから、適当なのもわからんでもないが……

なんか不毛な努力をしたな。 寝よ。

本日のツッコミ(全4件) [ツッコミを入れる]

Before...

% jijixi [あー、光沢液晶なんすね。それはちと寂しい。 MacBook とかだと BTO で液晶の種類選べた気がしますけど、iM..]

% cooldaemon [BTO でもダメでした。 テカテカを排除できるのは、MacBook Pro の 17 インチだけです。 あんな高いノ..]

% jijixi [> テカテカを排除できるのは、MacBook Pro の 17 インチだけです。 ぐっ、Apple の巧妙な罠が..]


2007-08-10 [長年日記]

% [clip][Erlang] Erlang, the next Java (Ralph Johnson - Blog)

きむらさんとこ経由。

Java より歴史の古い言語が、Java の次に来る言語になるかも……なんて笑い話みたいだなーと思いつつ、まあ、LISP のことなんかも考えれば歴史と流行に因果関係なんぞ無いんだろうなあ、とも。

もしあなたがこの先数年の間でマルチコアのアプリケーションを作ろうというのなら、 Erlangに注目すべきですにょ。

ちょwww 「にょ」てwww

% [clip] キツイ兄ちゃん (すべらない名無し)

とても心温まるツンデレ。

% [雑談] 久々に C のコードに潜ったら肩がこった

SWIG が吐いた Python 用のコード。 なんかすごく懐かしかったな。 そういや、いつから SWIG に触ってないんだろう?

% [Mac][雑談] 光沢がどーのこーのの前に、ガラスがはまってるのか!

参考→バラしのキーワードは、”アルミとガラス”(KODAWARISAN)

こんなの買っちゃったら、毎日画面を磨かないと気がすまなくなるじゃないか!!(謎


2007-08-13 [長年日記]

% [雑談] 今日も暑くなりそうだ

つか、すでに暑い。 気温はともかく湿度が高いのがイヤだなー。

% [雑談] 暑いので死にます

死んだらイヤなので、何か涼しいものでも買ってこようか。 ……涼しいものって何だ。アイスか?かき氷か? そんなありきたりなもんじゃなく、もっとズバッと問題を解決してくれるアイテムは無いのか。 あ、エアコンってのは無しの方向で。 そんなん買う金無いし、そもそも冷房病体質だからエアコン嫌いだし。

ちなみに北海道においては、エアコンてのは非常にブルジョアアイテムだと思うよ。 ほんとにエアコンが欲しくなるのなんて、どんだけ長く見積もっても二ヶ月程度だと思うし、たったそれだけのために用意するには高い買い物すぎる。

しかし、暑くて夜なかなか寝らんないし朝も寝てらんないから、わりと寝不足なんだけど、暑いから昼寝もする気になれんので、寝不足を解消するあてがない。 早く涼しくならんかなあ……


2007-08-14 [長年日記]

% [clip][雑談] 身長170の♀だけどどんなエロい質問でも答えるよ (鯉の笹焼き)

これは期待どおりのエロさwww

ちなみに、わしはこの手の 2ch スレ紹介系に関してほとんどは 2chnavi人気度:5以上の RSS から情報を得ているので、当然こういうタイトルのエントリの場合、内容はご想像の通りなのである。 まさか、タイトルまんまを期待して見に行く人はいないよね? ところで、店はつぶれたようだw


2007-08-15 [長年日記]

% [Scala][雑談] 関数オブジェクトとか何とか

関数オブジェクト (航海日誌) というエントリを見て、Java 方面から入ってくるとこうなるのか〜と、ちょっと驚いた。 関数型方面から入っていくと、あんな書き方しようなんてまず思わないと思う。

ともあれ、このエントリに対する普通のツッコミは、きっとみずしまさんがしてくれると思うので (ぉぃ) わしは単にこれをキッカケにしただけの雑談なぞを。

Scala には関数型的 (強いて言うと ML に近いかな) な側面と手続き型的 (というか Java 的) な側面が混在していて、なんというか、かなりキメラな言語になっている。 しかも DSL 用途を重視した設計になっているようで、"関数" と一口に言っても、様々な書き方で書けてしまう。 その一つが、リンク先で keisuken さんが書いてるようなのだったりするわけだ。

Scala の文法的に一番素直な関数の書き方はこう↓だろう。

scala> def f1(x:int) = { x + 1 }
f1: (int)Int

この関数を関数オブジェクト (この用語もどうなんだという気はするが) として使いたいなら、

scala> val f2 = f1 _
f2: (int) => Int = <function>

このように↑すると値として取り出せる。 もちろん、無名関数を作る文法があるので、

scala> val f3 = { (x:int) => x + 1 }
f3: (int) => Int = <function>

こんな↑風にも書ける。 ブレースに囲まれた部分が無名関数で、それを f3 という識別子に束縛している状態。 さらに、apply というメソッドを持ったオブジェクトは関数として振る舞うという仕組みがあるので、

scala> object f4 {
     |   def apply(x:int) = x + 1
     | }
defined module f4

こんな↑のも、これまで定義した関数と同じように使えたりする。

さて、ここまででも十分カオスっぽいけど、引数を取らない関数の話になってくると、さらに混沌としてくる。 まず、普通に def を使って定義するにしても、引数無しの場合は二種類の書き方がある。

scala> def g1() = { 1 + 1 }
g1: ()int

scala> def g2 = { 1 + 1 }
g2: int

一見 g2 の方は関数じゃないように見えるが、def で定義した場合には右辺は g2 が評価される度に評価されるので、れっきとした関数だ。 g1 と g2 の違いは型にも表われてるけど、呼び出しのときにカッコが必要か必要じゃないかである。

scala> g1()
res5: Int = 2

scala> g2
res6: Int = 2

scala> g1
res7: Int = 2

scala> g2()
<console>:5: error: g2 of type Int does not take parameters
  val res8 = g2()
               ^

あれ?以前は g1 って書くとエラーだった気がするけど挙動が変わったかな。 &g1 で関数オブジェクトを得る記法が廃止になった影響か?

……えーと、中途半端だし、まだまだ書けることは一杯あるんだけど、なんかこの辺りで急激にモチベーションが下がったので、とりあえず終了。 続きは気が向いたら書く。 というか、この辺の話は、一箇所にまとまってないけど、今までのわしの日記内に散在してるので、興味のある人はタグを利用したりして読んでみてくださいな。 ただし、Scala はまだまだ完全に文法や仕様が固まっている言語ではないので、書いてることを鵜呑みにせず現在の実装ではどうなってるかを確かめてみるのもお忘れなく。

そういや、みずしまさんの LL 魂での資料を見たけど、まとめのとこは笑ったね。グレート。 でも、配布されてるファイルが ppt だったりするのはグレートじゃない(苦笑

本日のツッコミ(全7件) [ツッコミを入れる]

Before...

% keisuken [やべ、捕捉された(^^;。 Scala初心者ということと、どうしても実装寄りで考えちゃうのですみません(anonym..]

% keisuken [それはそうと、Scalaは()がつくつかないがカオスな感じがしますね。 (私が意図的にああ書いちゃった理由として)単..]

% jijixi [Scala には、マクロや eval を使わずに DSL を柔軟に作れるようにしようというポリシーのようなものがある..]


2007-08-16 [長年日記]

% [雑談] ようやくすごしやすい気温に…

…なったのは良いんだけど、ギャップが激しすぎないかね。 昨日の同じ時間には 33 度くらいあったのに、今日は 27 度だよ。 身体がおかしくなりそうだ。

もう少しじわじわと下がってくれれば良いのに……ままならんなあ……

% [Python][雑談] そのインデックスに要素が存在するかわからないときの書き方を考える

要するに Ruby なら、

% irb
irb(main):001:0> [1,2,3][5]
=> nil

こうなのでウマーだけど、Python だと、

In [1]: [1,2,3][5]
---------------------------------------------------------------------------
<type 'exceptions.IndexError'>            Traceback (most recent call last)

/Users/jijixi/<ipython console> in <module>()

<type 'exceptions.IndexError'>: list index out of range

こんなだからショボーンだよね……というときに、どんな風に書くのが楽かという話。 この前 odz さんが「自分で拡張すればいいのに」とか書いてたけど、まあ、そこまでせんでも……という感じで。

で、要は指定したインデックスに値があるかどうか調べるという事なんだけど、一番無難なのは↓こんなだろうか。

In [4]: a = [1,2,3]

In [5]: if len(a) > 5:
   ...:     print a[5]
   ...: 

リストの長さが 5 より大きいならインデックスが 5 のところにアクセスしても out of range になることはない…という論法だね。 でもこれ、なんか妙に敗北感を感じるというか、どうも好きになれないんだな。 やってる事から意図が汲み取りにくいというか。 せめて、辞書の has_key に相当する has_index みたいなメソッドがあれば良いのにね。

…とか何とか、結構以前から永遠のテーマ (おおげさ) 的に考えていたりしたのだが、最近ふと気がついた。

In [7]: [1,2,3][5:]
Out[7]: []

お?

In [8]: [1,2,3][1:2]
Out[8]: [2]

おお? スライスを作るときには、out of range とか出ないんじゃん。 てことは……

In [9]: if [1,2,3][5:6]:
   ...:     print 'ok'
   ...: else:
   ...:     print 'ng'
   ...: 
ng

こんな風に書ける。 len を使うより断然短かい。ばんざい!!

……まあ、ますます意図が汲み取りにくくなってる気はするけども(汗

% [Scala][雑談] どこに重点を置くかで文法は変わってくるんだろうなーと思った

えーと、keisuken さんは……

foo a, b, c

と書きたいということなのかな? Rails が成功してるのって、この文法の効果も多少はあるような気がしてるんで、わからないでもない。 Rails ってある意味 Ruby とは別の言語になってるっぽいよね(笑

まあ、それはともかく、基本的に Scala の関数はカッコが必要なのが通常の形で、カッコがいらない書き方というのはむしろ特殊な形だと思った方が良いっぽい。 どっちかと言うと Ruby よりは Python 的なアプローチ。 一長一短だと思うけど、クロージャを使うときに Proc#call みたいなウザいヤツが必要無いので、個人的にはこっちの方が好みかも。

ちなみに代わりと言うわけでもないけど、Scala では……

scala> object Hoge {
     |   def f(x:int) = { println(x); this }
     | }
defined module Hoge

scala> Hoge f(1) f(2) f(3)
1
2
3
res0: object Hoge = Hoge$@acc95

こんな書き方ができたりする。 要するにメソッド呼び出しにドットじゃなく空白が使える。 これを利用すれば、何かおもしろいことができそうな気がしてるんだけど、ちゃんと考えたことはなかったり。

本日のツッコミ(全5件) [ツッコミを入れる]

Before...

% みずしま [> これを利用すれば、何かおもしろいこと DSLを作るときに、x or yみたいな中置演算子っぽいものが 定義でき..]

% jijixi [やっぱアレも DSL 用の機能なんですかねー。 後置 if のネタは Views を使ったときのカオスっぷりが笑えま..]

% morchin [> うは、すんごく富豪っぽい書き方ですね(笑 意識していませんでしたが確かに。 Pythonでは、set、lis..]


2007-08-17 [長年日記]

% [clip] 短すぎるパスワード/呪文は安全性の観点から好ましくない (檜山正幸のキマイラ飼育記)

「バル…」おっと危ねっ!!


2007-08-18 [長年日記]

% [clip][雑談] もう時効だから話す - はじめてのtcsh - ((ひ)メモ)

mmasuda さんとこより。

似たようなことやったことあるなあ(苦笑)。 どういうシチュだったかは憶えてないけど、何か無限にプロセスが生成されんの。

ただ、FreeBSD だとこういうことやっちゃっても、かろうじて何とかなるのね。 まあ、何とか、と言っても結局再起動したりするのがオチだけど。 でも最近どうなってるかは知らないけど、何年か前までは Linux でこういうことやると、もうリセットボタンしか手が無かったんだよな。 要するに超高負荷時の応答性に結構違いがあった。 特に仮想メモリがスラッシングをし始めると、もうまったく何もできなかった憶えがある。

いまだに「PC-UN*X を使うなら Linux より BSD 系」と思ってしまう背景には、そういう経験があったり。

% [clip][Erlang][Python][雑談] 分散関数呼び出し (DouKaku?)

lethevert さんのとこほか経由。

なんですかこのErlangで書けといわんばかりのお題は?

マジレスしますと。 このお題の投稿者は沢渡みかげさんという人で、この人はたぶんみかログの人なので、お題の最後に書いてある…

出題の意図は,様々な分散呼び出し方法の実装例と, レスポンス速度の確認にあります.

というのは、まず Erlang での例があって、同じことやるときにその他の環境のパフォーマンスデータが欲しいという意図に違いありますまい。 (実際 Erlang の例はこの方が書かれてますな)

なので、問題のベースが Erlang ありきなのに Erlang で書いたってバカバカしいですよと暴言を吐いとこう。 とりあえず、今現在だと Parallel Python で書いてる人がいないみたいなんで狙い目だと思われ。 誰か書かない?

あと、どうしても Erlang で書きたい人はサーバ側のノードはただ何もせず立ち上げるだけで、必要なものは全部クライアント側から送るくらいのことしないとつまんないと思う。 一応参考にこれとかこれとか挙げとこう。 手前味噌だけど。

ところで、

作成した関数を直列に1万回呼び出して,

ということなら、わざわざサーバプロセスのようなものを作らなくても、rpc:call で十分だと思う。(参考)


2007-08-19 [長年日記]

% [Python] 分散関数呼び出しを Parallel Python で書く

カンマの処理が案外めんどうで、locale モジュール使ってごまかそうと思ったら環境によってうまくいったりいかなかったりで、いいかげんイヤになったから省くことにした。 ので、題意に沿ってないから投稿はせずに、ここに書くだけにしとく。

ちなみにユニコード文字列をあえて使ってないのも、環境依存のめんどうさがあるから。 なんかユニコード文字列のマーシャリングで、非互換とかあるのかなあ… (つーか、こいつも locale が絡むんだっけ?)

% cat rcall.py
import pp

def pricestring(price, discount):
    return '販売価格 %s 円 (定価 %s 円から %s %% 引き)' % \
           (price*(100-discount)/100, price, discount)

def pricestring_remote(server, price, discount):
    ret = server.submit(pricestring, (price, discount))
    return ret()

def main():
    from optparse import OptionParser
    parser = OptionParser()
    parser.add_option('-s', '--server', metavar='HOST',
                      help="hostname or IP address of pp server")
    parser.add_option('-n', '--number', metavar='INTEGER',
                      default=100, type='int', help='number of call')
    parser.add_option('--local', action='store_true',
                      default=False, help='execute on local')
    (opts, _) = parser.parse_args()
    price, discount = 2000, 20
    if opts.local:
        for _ in xrange(opts.number):
            print pricestring(price, discount)
    else:
        if not opts.server:
            parser.print_help()
            parser.exit()
        server = pp.Server(0, ppservers=(opts.server,))
        for i in xrange(opts.number):
            print pricestring_remote(server, price, discount)

if __name__ == '__main__':
    main()

使い方は、まずどっかのホストで Parallel Python のサーバを立ち上げる。

remotehost% python -m ppserver

あとは、別のホストで (や、同じホストでも良いが)、

localhost% python rcall.py --server remotehost -n 10

とかやれば、

販売価格 1600 円 (定価 2000 円から 20 % 引き)
販売価格 1600 円 (定価 2000 円から 20 % 引き)
販売価格 1600 円 (定価 2000 円から 20 % 引き)
...(以下略)

てな感じで表示されるはず。 ソースコードの文字コードと端末の文字コードが違ってると文字化けするが、その辺はあえて気を使ってないところなんで、それはそれで良いことにする。

最後に書いてみた感想。

  • グローバルな状態を持つようなモジュール (例えば locale とか) を使う場合、動きが怪しい
    • そもそもサーバ側でどういう状態になってるのか、全然わからん
  • ユニコード文字列の扱いが怪しい
    • わしが試した環境が MacOSX/PPC64 と FreeBSD/i386 という組み合わせだから尚更という話もありそうだが
    • だとすれば、Parallel Python でクラスタを作ろうと思ったら、アーキテクチャと OS は揃えた方が良いのかも知れず
    • この辺をまったく心配しなくて良い Erlang は、やっぱ偉大だなあ

% [Python] Parallel Python でユニコード文字列がうまく扱えない件

pickle モジュールの問題かと思ってたが、どうも inspect モジュールの問題 (というか仕様?) のような感じ。 Parallel Python (長いので以下 pp と書く) が分散処理をする仕組みというのは、簡単に書くと、

  • inspect モジュールで必要な関数のソースを取得
  • pickle モジュールでマーシャリング (シリアライズ言うなキャンペーンに賛同しています :-p)
  • マーシャリングした文字列をサーバに送って処理させる
  • 結果がやっぱりマーシャリングされて戻ってくる

という流れ。 なのでまあ、pickle 絡みが怪しいと踏んでたんだけど、そもそも inspect した時点でソースコードに書いてあるユニコードリテラルは (ある意味で) 腐っているのであった。 例えばこんなソースコードがあったとしよう。

% cat test.py
# -*- coding: utf-8 -*-
def main():
    print u'ほげほげ'
main()

Python の文字コードの扱いの仕組み的には、UTF-8 で書かれた u'ほげほげ' というリテラルは、このファイルが読み込まれる時点で UCS2 か UCS4 の内部表現を持ったユニコード文字列のインスタンスに自動的に変換される (はずだ)。 んで、print されるときに、locale に応じた文字列 (うちの場合は euc-jp) に変換される。 なので、LANG=ja_JP.eucJP と設定されている端末であっても、

% python test.py
ほげほげ

というように、文字化けせずに表示されてメデタシメデタシという寸法。

さて、ではこのコードを pp がやっているのと同じ方法で取得してみよう。

In [1]: import inspect
In [2]: import test
ほげほげ
In [3]: s = inspect.getsourcelines(test.main)
In [4]: s
Out[4]: 
(['def main():\n',
  "    print u'\xe3\x81\xbb\xe3\x81\x92\xe3\x81\xbb\xe3\x81\x92'\n"],
 2)

この通り、文字コードに関する情報はキレイさっぱり消えている。 そして、このソースコードは pp のサーバに渡された後、単純に eval される。 これが何を意味するかというと、サーバ側の Python のデフォルトエンコーディングが "たまたま" このコードと同じものに (つまりここでは utf-8 に) 設定されていない限り (そして、たぶんそんなことはまず無い)、このユニコード文字列は文字化けする運命にあるわけ。

とりあえず、いろいろ試してみた感じとしてはユニコードリテラルを正しく扱うのは難しそうなので、pp を使うときにはソースコード中にユニコードリテラルは含めないようにするのが良さそう。 要は、

u'ほげほげ'

ではなく、

'ほげほげ'.decode('utf-8')

とでも書いておくのが無難だろう。

本日のツッコミ(全6件) [ツッコミを入れる]

Before...

% jijixi [話が前後しましたが、スクリプトの頭にエンコーディングの指定が書かれていると、それに応じて u'hogehoge' と..]

% きむら(K) [> python では重要なのね。 Pythonだけじゃないですよ。 起源は多分Emacsです。幾つかの言語やエディ..]

% jijixi [ちなみに Python では Emacs 形式か Vim 形式のモードラインを解釈することになっているので、(と言う..]


2007-08-20 [長年日記]

% [Python] Python におけるマルチバイト文字の扱いをまとめてみる

Python のマルチバイト文字の扱いって、ちょっとクセがあるというか直感に反するところがあって、理解するまでちょっと手間取った記憶があるので、この際だから簡単にまとめてみようかと思う。 完全に把握しているわけではないので、間違いとか見付けたらツッコミよろしく。 文字コード名はめんどうなので正式名称とかにこだわらずに、Python が正しいと認識してくれるなら何でも良いやというノリで書いているので、細かいところはあんまり気にしないでいただきたい。

基本事項

  • Python の文字列には二種類がある (厳密には違うけど、ここではあまり関係無いので省く)
    • string
      • 伝統的な文字列
      • ぶっちゃけバイト列
    • Unicode string
      • 内部コードに UCS2 または UCS4 (処理系のコンパイル時に決まる) を使った文字列 (以下では面倒なので内部コードは UCS2 であると仮定して書く)
      • Python3000 では文字列はこれに統一されるとか、されないとか?

文字コードに関する事

  • Python においては、マルチバイト文字に関する事柄は全て Unicode string (UCS2) が基本にある
  • つまり、例えば euc-jp の文字列は Python 的に見ると「euc-jp にエンコードされたバイト列」という意味
  • 故に、euc-jp で表わした 'ほげ' は、UCS2 で表わした 'ほげ' を euc-jp でエンコードしたものという認識になる
    • '\xa4\xdb\xa4\xb2' = u'\u307b\u3052'.encode('euc-jp')
  • 逆に、euc-jp で表わした 'ほげ' をデコードすることで UCS2 の 'ほげ' になる
    • '\xa4\xdb\xa4\xb2'.decode('euc-jp') = u'\u307b\u3052'
  • 個人的に、慣れるまでこの対応が逆に思えて仕方がなかった
    • とりあえず、string (バイト列) から Unicode string を得るには unicode 関数を使うとわかりやすい
    • 上記の encode とか decode メソッドの引数 'euc-jp' を省略すると、Python のデフォルト文字コードが使われる
      • Python のデフォルト文字コードは sys.getdefaultencoding() で取得可能
      • 通常の Python (CPython) ではインタプリタの起動後にこれを設定するのは不可能なので、設定したいときは site-packages/sitecustomize.py を用意する→参考リンク
  • ファイルオブジェクトには encoding という属性があって、これが None じゃない場合、そのファイルオブジェクトに Unicode 文字列が渡されると自動的に encoding が示す文字コードに encode される
    • sys.stdout.encoding は LANG 環境変数の値から設定されているので、LANG が正しく設定されているなら print u'ほげ' とかは文字化けしない
    • encoding の値が None の場合は (普通にファイルを開いた場合なんかは、そうなる) やっぱり Python デフォルトの設定が使われる
      • まあ、ファイルに書き込むときは、明示的に str.encode('euc-jp') とかやっといた方が無難だと思う。

リテラルに関する事

  • ソースコード中に書かれた 'hoge' という文字列リテラルは、単純に string (バイト列) としてそのまま読み込まれる
    • つまり、'ほげ' が euc-jp で書かれていれば '\xa4\xdb\xa4\xb2' だし shift-jis なら '\x82\xd9\x82\xb0' になる
  • ソースコード中に書かれた u'hoge' という Unicode 文字列リテラルは、ファイルの先頭に記述された encoding 指定によって UCS2 にデコードされる
    • ファイルの 1 行目か 2 行目に # -*- encoding:euc-jp -*- などと書かれていて、実際に euc-jp で u'ほげ' と書かれていれば、u'\u307b\u3052' になる
      • もちろん、指定と実際の文字コードがちぐはぐなら正しい Unicode 文字列にはならない (と言うか、大抵は読み込み時にエラーになるだろう)
    • ファイル中に文字コードの指定が無い場合は Python のデフォルト値でデコードされる……と思ってたんだけど、今試したら嘘だった ('ascii' でデコードしようとするみたい)
      • Unicode リテラルを含むソースコードには必ず encoding の指定をしよう

対話環境に関する事

  • 素の対話環境の場合、sitecustomize.py と端末の文字コード設定を合わせておくことで普通に Unicode string が使える
  • IPython の場合、最近のバージョンだとマルチバイト文字は utf-8 として保持するようになっている模様
    • 要するに euc-jp な端末で 'ほげ' と入力しても '\xe3\x81\xbb\xe3\x81\x92' になる
      • たぶん、sys.stdin.encoding に応じてごにょごにょしてるんじゃないかと (ソース読んだわけじゃないけど)
    • てことで、特に設定しなくても普通に Unicode string が使えるようになっていると思われる
      • ただし、上に書いたように何が何でも utf-8 になってるので、euc-jp な端末で 'ほげ'.decode('euc-jp') とか書くと謎のエラーに悩まされることに ('ほげ'.decode('utf-8') と書こう)

2007-08-21 [長年日記]

% [Ruby][雑談] 関数型脳になると、ちょっとイラっとする Ruby の要素

例えば、あるハッシュをいじって別のハッシュを作りたいときがある。 関数型脳なんだから、当然のように元のハッシュを書き換えるんじゃなく、新たなハッシュを作りたい。

ここで、手続き型脳で考えた場合、話は簡単だ。

irb(main):001:0> a = { :hoge => 1, :fuga => 2, :piyo => 3 }
=> {:hoge=>1, :fuga=>2, :piyo=>3}
irb(main):002:0> b = {}
=> {}
irb(main):003:0> a.each do |k,v|
irb(main):004:1*   b[k] = v + 1
irb(main):005:1> end
=> {:hoge=>1, :fuga=>2, :piyo=>3}

こう書けば良い。 でも、関数型脳で考えると、こういうシチュエーションはどうしても map を使いたくなる。

irb(main):006:0> c = a.map do |k,v|
irb(main):007:1*   [k, v + 1]
irb(main):008:1> end
=> [[:hoge, 2], [:fuga, 3], [:piyo, 4]]

とりあえず、結果を直接ハッシュにできないことには文句は言うまい。 それは良いのだが、ここでできた assoc array をすっきりハッシュに変換する方法が無いのが困る。 例えば Python なら、

In [1]: dict([['hoge',2],['fuga',3],['piyo',4]])
Out[1]: {'fuga': 3, 'hoge': 2, 'piyo': 4}

てな感じで、一発で辞書に変換できるんだが、Ruby にはこういう手段が無いっぽい。 しかたないので、今のところは

irb(main):009:0> Hash[*c.flatten]
=> {:hoge=>2, :fuga=>3, :piyo=>4}

とか書いてるんだけど、「なんぞこれ?」って感じだよね。 せっかくすでにマップ構造に適した形になってるものを、なんでわざわざ平らにならすの? …とか、コメ印ウザ…とか。 だからと言って、

irb(main):010:0> d = {}
=> {}
irb(main):011:0> c.each do |k,v|
irb(main):012:1*   d[k] = v
irb(main):013:1> end
=> [[:hoge, 2], [:fuga, 3], [:piyo, 4]]

こんなことやっちゃうと、本末転倒だし。

irb(main):023:0> c.inject({}) do |result,pair|
irb(main):024:1*   k,v = pair
irb(main):025:1>   result[k] = v
irb(main):026:1>   result
irb(main):027:1> end
=> {:hoge=>2, :fuga=>3, :piyo=>4}

これはちょっと冗長すぎる。 ……やっぱ諦めて最初の方法で書くのが一番良いのかねえ。

ところで、あたかも Python なら全てが解決…みたいな風に読めたかも知れないが、そんなこともなくて…

In [1]: map(lambda (k,v): (k,v+1), {'hoge':1,'fuga':2})
ERROR: Internal Python error in the inspect module.
Below is the traceback from this internal error.
(...略...)
<type 'exceptions.ValueError'>: too many values to unpack

Python の場合は辞書をそのまま map に使えなかったり。 これは map が要求するのはシーケンス型なのに、辞書はシーケンスじゃなくマップ型だから。 上の例では、辞書は自動的にリストに変換されていて、残念なことに、それはキーのリストだったりする。 んで、正しくはこう↓する。

In [2]: map(lambda (k,v): (k,v+1), {'hoge':1,'fuga':2}.iteritems())
Out[2]: [('fuga', 3), ('hoge', 2)]
In [3]: dict(_)
Out[3]: {'fuga': 3, 'hoge': 2}

ちなみに、In[3] で使ってるアンダースコアは、irb と同じで直前に評価した式の値が入っている特殊変数。 たしか、IPython だけじゃなく素の Python インタプリタでも使える。

% [Ruby] ActiveSupport::OrderedHash に絶望した

なんか ruby-list で名前が挙がってたんで、ちょっとソース見てみたんだけど……

まあなんつーか、名前の気持ち悪さはこの際置いておこう。 Ruby におけるマップ構造の代名詞はハッシュなわけだし、そういう意味で OrderedMap と名付けるべきであってもあえて OrderedHash と付けた、ということなら納得もしよう。 実際のところは知らないが。

……うん、でまあ、ソースを見たんだ。 正直絶望した。 うーん、なんていうのかなあ、こういうの ordered って言うの? 元々の言葉の意味はともかく、コレクション構造を扱う文脈で ordered と言ったら、sorted とほぼ同義なんじゃないのかねえ。 この作りだと、それこそ元質問者が想定してたような「入れた順に出てくる」だけのものなんだけど。

本日のツッコミ(全9件) [ツッコミを入れる]

Before...

% odz [Java には LinkedList からの連想なのか LinkedHashMap なんてのがありますね。これもどう..]

% jijixi [> LinkedHashMap なんというカオス(笑 どういう構造なのか謎すぎる。]

% odz [> どういう構造なのか謎すぎる。 たしかに名前だけだと謎ですね。 単に、hash table と挿入順に並べた l..]


2007-08-22 [長年日記]

% [clip][Python] Python NetWorkSpaces(NWS)と並列プログラミング

どこ経由で見付けたのかは失念。 RSS リーダで読みながらポチポチ適当にリンクをタブに開いておいて後で読む…というやり方をしていると、こういうとき困る。(RSS リーダだと読んだ履歴が残らないから)

Python (と R) で分散・並列プログラミングを行なうライブラリである NetWorkSpaces の紹介。 このページの翻訳らしい。

NetWorkSpace と呼ばれる、ある種のプロセス間通信チャンネルを使って値をやり取りしながら並列計算を行なおうという仕組みのようだ。 さっそくインストールして試してみる (nwsserver と nwsclient)。 インストール方法は標準的な Python の方式なので省略。 Erlang で言う epmd みたいなサーバプロセスが必要みたいなんだけど、それが Twisted を使うみたいなんで、これも入れておく。 ちなみに、MacOSX でフレームワーク版の Python (オフィシャルで配布されてるのとか) を使っている場合は、/Library/Frameworks/Python.framework/Versions/Current/bin にコマンドがインストールされるので、適当にリンク貼るなりパスを通すなりするのが吉。

で、インストールは完了しているものとして、サーバを起動。

% twistd -y /Library/Frameworks/Python.framework/Versions/Current/nws.tac

環境によって nws.tac がどこにインストールされるかはわかんないけど、まあ適当に探してちょうだい。 ではいよいよいじる。 python を起動 (以下 hoge と呼ぶ)。

% ipython -pi1 'hoge: '
hoge: from nws.client import NetWorkSpace
hoge: ws = NetWorkSpace('foo')

まず foo という名前でワークスペース (以下 ws) を作る。

hoge: ws.store('bar', 'hogehoge')

ws に bar という名前で 'hogehoge' という文字列を登録。 ここでおもむろに別の python を起動 (以下 fuga)。

% ipython -pi1 'fuga: '
fuga: from nws.client import NetWorkSpace
fuga: ws = NetWorkSpace('foo')

同じ名前 ('foo') で NetWorkSpace のインスタンスを作ると、同じサーバ上に既存のものがある場合にはそれが共有される。 つまり hoge 上の ws と fuga 上の ws は同じものを指している。

fuga: ws.find('bar')
Out[3]: 'hogehoge'

このように、hoge で登録した文字列が fuga で取り出せた。

ワークスペースはイメージ的には複数の同期チャンネルを束ねるものという感じだね。 一つのワークスペース内に、名前を付けることで別々のチャンネルが同時に存在している感じ。 これは、なんとなく Erlang のメールボックスのような使い方ができそうな気がする。

hoge: ws.store('a', 1)
hoge: ws.store('b', 2)
hoge: ws.store('c', 3)

こんな状態で、

fuga: ws.find('a')
Out[7]: 1

a の値だけ選んで取り出すことができるわけで。

全体的に Parallel Python より筋が良い感じはするけど、あれにはあれで良いところもあるので一概に優劣は付けられないかな。

hoge: def f(x): return x + 1
hoge: ws.store('f', f)
fuga: f = ws.find('f')
(...略...)
<type 'exceptions.AttributeError'>: FakeModule object has no attribute 'f'

こんな感じで、こういうことやるのに簡単な方法はざっと見た感じ用意されていないっぽい。 ……と思ったら nws.sleigh モジュールの方でなんかできそうにも見えるな。 後でまた調べよう。

とりあえずは、ここまで。

% [Ruby] YAML.dump がマルチバイト文字をちゃんと扱ってくれなくて絶望した

あるテキストを解析したデータを適当に整形してファイルに落としたい、という要求があって、自分で整形するのはめんどいから YAML.dump で何となくオッケーじゃん?とか思ったわけ。

……なんだけど日本語の文字列が全くまともに出力されなくて、ひどく悩む。 ちゃんと UTF-8 にしてんだけどなー ……が、結局解決法がわかんなくて、とりあえず仮に pretty_inspect して書き出すようにごまかしといた。

で、一段落してようやくググる。 あー、そっすか。そもそもがダメダメだったんすね。 とりあえず、今回はともかくいずれ何か困ることにもなりそうな気がするからリンクをメモっとこー

本日のツッコミ(全2件) [ツッコミを入れる]

% cooldaemon [社内では、角谷氏のモジュールを使ってます。 それでも perl の YAML.pm と挙動が異なるので困る事が(汗]

% jijixi [言語ごとに挙動が違うのはある程度しかたないにしても、読み込めるのに同じように書き出せないのはショックでかかったですね..]


2007-08-23 [長年日記]

% [Python] NetWorkSpaces の nws.sleigh モジュール

せっかく昨日夜更かししてソースを読んだので (おかげで今日は寝坊したが :-p) 軽くまとめておく。 じっくりいじってる暇が無いので、実際にそのように動くかどうかは不明。 週末にでも気力があればいじろう。

  • なんで Sleigh (そり) なんつー名前なの?
    • 知りません。
  • 何をするもの?
    • 端的に言って、nws.sleigh.Sleigh クラスは Parallel Python の pp.Server クラスと同じようなもの
    • 要するにワーカプロセスのプールを作って、タスクを与えると適当にそれらに割り振って分散処理してくれる仕組み
  • ワーカプロセスはローカルにもリモートにも作成できる
    • リモートにワーカを作る場合は、そちらにも必要なモジュールが用意されていることが前提
    • リモート側に何らかのサーバプロセスを用意しておかなくても、ssh などを使ってワーカを起動させることができる → Sleigh(launch=nws.sleigh.sshcmd, ...)
  • ワーカにタスクを渡すとき、関数ならその関数のオブジェクトコード、インスタンスメソッドならその self オブジェクト (とメソッド名) を渡して (もちろんマーシャリングする) 実行させる
    • pp に比べるとクールな感じはするけど、Python のオブジェクトコード (バイトコード) ってポータビリティが微妙なんじゃなかったっけ?
      • だとすると、ワーカは同じアーキテクチャのホストに作るようにしないと使い物にならん可能性が (いずれ実験したい)
      • つーか Python って同じアーキテクチャ同じ OS でもコンパイルオプションによっては環境非互換があるんだよな (Unicode 文字列とか)。そういうのってどうなってんだろ?
  • 基本的に使うのは eachElem メソッド
    • ぶっちゃけ Erlang の rpc:pmap
    • キーワード引数で blocking=False を指定すると値が直接返るのではなく、SleighPending というクラスのインスタンスが返る
      • これは check メソッドで値が全て返ってきてるか確かめたり、wait メソッドで値を取り出す (check が False を返すような状態ならブロックする) ことができる
  • 他には imap とか starmap とか
    • itertools 互換 (だと思う)

とりあえずこんなとこ。

% [雑談] 小汚い html ファイルを解析することの不毛さに疲れきった

xhtml 万歳(疲

% [Python][雑談] 素の Python では関数コードオブジェクトを pickle できないが Stackless ではできる件

だから何がどうなる?ってのはよくわからんのだけど、まあ、たまたま気付いたのでメモ。

まず素の Python 2.5

In [1]: import pickle
In [2]: f = lambda x: x+1
In [3]: pickle.dumps(f)
---------------------------------------------------------------------------
<class 'pickle.PicklingError'>: Can't pickle <function <lambda> at 0x84b7fb4>:
 it's not found as __main__.<lambda>

In [4]: pickle.dumps(f.func_code)
---------------------------------------------------------------------------
<type 'exceptions.TypeError'>: can't pickle code objects

うぬー

In [5]: pickle.dumps(f.func_code.co_code)
Out[5]: "S'|\\x00\\x00d\\x00\\x00\\x17S'\np0\n."

これだけ↑はできる。 ただ、これだけあっても関数としての意味を為さないので他の co_* 属性もちゃんとしないといけないはず。

で、Stackless 2.5

In [1]: import pickle
In [2]: f = lambda x: x+1
In [3]: pickle.dumps(f)
---------------------------------------------------------------------------
<type 'exceptions.TypeError'>: can't pickle file objects

これは無理だったが、(ところで、エラーメッセージ変じゃね?)

In [4]: pickle.dumps(f.func_code)
Out[4]: "cstackless._wrap\ncode\np0\n(I1\nI1\nI2\nI67\nS'|\\x00\\x00d\\x00\\x00\\x17S'\n
p1\n(I1\ntp2\n(t(S'x'\np3\ntp4\nS'<ipython console>'\np5\nS'<lambda>'\np6\nI1\nS''\np7\n
(t(ttp8\nRp9\n(tb."

これは大丈夫 (長いので出力には改行を入れてある)。 何でこういう違いがあるのかよく知らないが、Stackless では tasklet (スレッド) をマーシャリングする機能があったはずだから、そのために拡張されてるのかもしれない。

本日のツッコミ(全2件) [ツッコミを入れる]

% cooldaemon [http://blog.labnotes.org/category/scrapi/ HTML のスクレイプは、これ使..]

% jijixi [お、どうもっす。 クリップクリップっと。]


2007-08-24 [長年日記]

% [Ruby][Erlang] Erlang Message Passing - Ruby point of view (DZone Snippets)

via Matzにっき

どうにも気持ち悪いコードだなあ。 こういう構成なら receive はともかく send はプロセス自体に持たせるもんじゃないだろ。 何でもオブジェクトに閉じ込めれば良いってもんじゃないと思うが……

Matz さんのリクエストに応えて…とかおこがましいことを言うつもりはないけど、つい流れを追いかけてしまったので、せっかくだから解説っぽいものを。

ErProc クラスは @thr というメンバにスレッドを一つ持つ。 で、そのスレッドで実行されるメソッド func は、receive でメッセージが送られてくるのを待って、メッセージを受け取ったらそれを起動時に受け取った引数 (使ってる例だと次の ErProc) に送る (send する) というもの。

とりあえず、ここまでは良い。 でも receive と send の実装が結構キモい。 receive は自分自身で呼ぶのに対して、send は自分以外が呼ぶ、という前提をわかってないと何をやってるのかわかりにくいと思う。 要するに、receive と send では呼ばれた時点の Thread.current が違うってことね。 こんなものを一つのオブジェクトに閉じ込めるのは、ちょっといただけないと思う。

ところで今ようやく気付いたが、何か変な違和感があるなと思ってたら receive の綴りが間違っとるぞ、このコード(苦笑

さて、では send メソッドから見ていくが、このメソッドはさっきも書いたとおり自分以外の誰かが呼ぶ。 具体的に言えば、別のスレッドから呼ばれる。 send メソッドを持っているオブジェクトを self 、それを呼び出すスレッドを other とすると、現在動いているのは other である。

other が self の send メソッドを呼ぶと、まず Thread.critical を真にして他のスレッドにスイッチしないようにする (ちなみに、この状態で Thread.stop が呼ばれると、Thread.critical は自動的に偽になる)。 self が stop の状態 (後で書くけど基本的には receive を呼ぶとそうなる) じゃない場合は self の @waiter に other を格納して other は stop する。 self が stop の状態になると (これまた後で書くけど receive するときに @waiter を起こすので) other は動き出して self の @data にデータを書き込み、self の @thr (receive 待ちしているスレッド) を起こす。 もちろん、最初から self が stop 状態でも同じ事が起こる。

次に receive 側。 self が receive を呼ぶと、Thread.critical で排他制御をしつつ、@waiter が nil じゃない場合 (要は self の send を呼んで待っている other がいる場合) @waiter を起こす。 この時点で other に制御が移るし、@waiter が nil だった場合には自分で Thread.stop を呼んで寝るので、とにかくここで self のスレッド @thr は止まった状態。 で、さっきの説明どおり、いずれ other が @data にデータを書き込んで @thr を起こすので、その後 @data を return して終了。

ほんで、この send と receive を実際に使ってるのが func メソッド。 これもすでに書いたけど、receive を呼んでメッセージが送られてくるのを待って、引数に与えられた別の ErProc に receive したデータ (の二個目の要素に +1 してから) を送っている。 ただし、引数に ErProc が与えられていない場合は、データをグローバル変数 $data に格納してメインスレッドを起こす。 この状態ってのは、この後実際に作られるプロセスチェーンの最後の部分の状態。 メインスレッドはチェーンの頭にメッセージを送った後 stop していて、ここで起こされると $data の値を表示して終了。 (実際は ARGV[1] の回数分ループだけど)

他のメインスレッドでやってる部分は、わかるでしょう。 ARGV[0] の個数分のプロセスチェーンを作って、先頭…というか最後尾(?)にメッセージを送ることを ARGV[1] 回繰り返して、最後にかかった時間を出力して終了。

全体的に見て、そもそも Thread.critical で排他制御をするな (あてにするなとマニュアルにも書かれている) という話もあるけど、それ以外にも微妙に気になる部分はある。 まあ、わしも Ruby のスレッドはあんまり使ったことないんで、マニュアルの記述を鵜呑みにしただけの状態での感想だけど……

例えば、stop しているスレッドを wakeup で起こしてるけど、マニュアルの Thread#run の説明を読むかぎり、wakeup では「すぐに」そのスレッドに制御が移るかどうかは保証されない。 ということは (すごくレアケースではあるだろうけど) receive メソッドで @waiter.wakeup した後、@waiter が動きだす前にそのまま send によって @data が更新される前に return @data まで行ってしまう可能性が無いとは言えないんじゃなかろうか。

他にも send で Thread.stop した場合の復帰後は @data に排他制御無しで書き込んじゃうとか、細かく気になる部分がある。 まあ、この程度の例ではたぶん問題になることは無いと思うんだけど、これがもっと複雑なものになってくるとこういう細かい不穏因子が怪しげな挙動を引き起こす可能性は十分ある……というのが共有メモリ型のマルチスレッドプログラミングの難しさを物語ってる気がするなあ。


2007-08-25 [長年日記]

% [Ruby][Erlang] Ruby で Erlang のプロセスもどき

昨日のリングベンチマークの話にちょっと触発されて、なんとなく作ってみた。 空行をある程度切り詰めても 100 行くらいあるので、先に説明をしてソースコードは最後に貼る。

irb(main):001:0> require 'erloid'
=> true
irb(main):002:0> p1 = spawn do
irb(main):003:1*   receive [
irb(main):004:2*     [:hoge, proc{|x| p x}]
irb(main):005:2>   ]
irb(main):006:1> end
=> #<Erloid::Process:0xdfc0 sleep>
irb(main):007:0> p1 << [:fuga, 'fuga']
=> [#<Erloid::Process:0xdfc0 sleep>, [:fuga, "fuga"]]
irb(main):008:0> p1 << [:hoge, 'hoge']
"hoge"=> [#<Erloid::Process:0xdfc0 run>, [:hoge, "hoge"]]

こんな感じ。 erloid という名前は Erlang (erl) のもどき (-oid) という意味。 receive にはブロックじゃなくパターンを列挙した assoc array を渡す。 順番がどうでも良いならハッシュでも良いけど。 要するにこんな↓ことができる。

irb(main):018:0> p2 = spawn do
irb(main):019:1*   receive [
irb(main):020:2*     [:hoge, proc{|_| p 'hoge'}],
irb(main):021:2*     [:fuga, proc{|_| p 'fuga'}],
irb(main):022:2*   ]
irb(main):023:1> end
=> #<Erloid::Process:0x3cbb8 sleep>
irb(main):024:0> p2 << :fuga
"fuga"=> [#<Erloid::Process:0x3cbb8 run>, :fuga]

p2 に :fuga というキーを送ったので :fuga にマッチするパターンが実行される。 メッセージ送信 (<< メソッド) の書式は、

process_obj << key
process_obj << [key, value]

で、key だけの場合は実質 [key,nil] を送るのと同じ。 receive の書式は、

receive [
  [key, proc or value],
  ...(複数可)
]
receive({
  key => proc or value,
  ...
})

で、プロセスのメールボックスに key がマッチするデータが入っていれば、proc に key に関連付けられた値を渡して実行される。 proc の部分は単なる値でも良くて、その場合はその値が receive の返り値になる。 ブロックではないので、ハッシュを使うときはカッコを忘れずに (むしろ外側の波カッコを省くという手もあるが…)。 key の部分を nil にするとワイルドカードパターンになって、一番古いメッセージが処理される。 マッチするメッセージが無い場合は、それが来るまでブロック。

テストとかはろくにしてないので (と言うか、ががーっと書いてそのまんま)、たぶんバグはあると思うけど、とりあえずこんなもんで。 リングベンチまで書こうと思ったけど、なんかめんどくさくなったからやめた(ダメ

そんなとこで、以下ソースコード。 どうでもいーけど、Array#assoc は機能が中途半端で使いにくいなあ。 結局必要な機能を自分で書くはめになったじゃないか。

% cat erloid.rb
require 'thread'
module Erloid; end

class Erloid::ArrayMap < Array
   alias orig_get :[]
   alias orig_set :[]=
   alias orig_shift shift
   private :orig_get, :orig_set, :orig_shift
   def get_index(key)
      index = each_with_index do |v,i|
         k,_ = v
         break i if k == key
      end
      if index.object_id != self.object_id
         index
      else
         nil
      end
   end
   def get_value_with_index(key)
      if (idx = get_index(key))
         _,v = orig_get(idx)
         [v, idx]
      end
   end
   def [](key)
      v,_ = get_value_with_index(key)
      v
   end
   def get!(key)
      v,i = get_value_with_index(key)
      delete_at(i)
      v
   end
   def has_value?(key)
      get_index(key)
   end
   def shift
      _,v = orig_shift
      v
   end
   def []=(key,val)
      self << [key, val]
   end
end

class Erloid::MailBox
   def initialize
      @buffer = Erloid::ArrayMap.new
      @mutex  = Mutex.new
      @cond   = ConditionVariable.new
   end
   def <<(msg)
      @mutex.synchronize do
         key,val = msg
         @buffer[key] = val
         @cond.signal
      end
   end
   def receive(alist)
      @mutex.synchronize do
         while true
            alist.each do |key,block|
               break if @buffer.empty?
               next if not (key.nil? or @buffer.has_value?(key))

               value  = if key.nil?
                           @buffer.shift
                        else
                           @buffer.get!(key)
                        end
               result = if Proc === block
                           block.call(value)
                        else
                           block
                        end
               return result
            end
            @cond.wait(@mutex)
         end
      end
   end
end

class Erloid::Process < Thread
   def initialize(&block)
      @mailbox = Erloid::MailBox.new
      super(&block)
   end
   def <<(msg)
      @mailbox << msg
      [self,msg]
   end
   def receive(alist)
      @mailbox.receive(alist)
   end
end

module Kernel
   def spawn(&block)
      Erloid::Process.new(&block)
   end
   def receive(alist)
      Thread.current.receive(alist)
   end
   private :spawn, :receive
end

2007-08-26 [長年日記]

% [Ruby][Mac] 今日は一日 Fiber とたわむれようと思ったけど空振った件

手元にあった Ruby 1.9 が 8/18 時点のものだったので、22 日に入った新仕様の Fiber をいじろうと思って trunk をビルド。 make test で止まらないテストがあるのに不安を覚えつつも、まーいーやって感じでインストール。

% irb19
irb(main):001:0> Fiber.new { p 'hello' }
TypeError: allocator undefined for Fiber
        from (irb):1:in `new'
        from (irb):1
        from /usr/local/lib/ruby/1.9/irb.rb:150:in `block (2 levels) in eval_input'
        from /usr/local/lib/ruby/1.9/irb.rb:259:in `signal_status'
        from /usr/local/lib/ruby/1.9/irb.rb:147:in `block in eval_input'
        from /usr/local/lib/ruby/1.9/irb.rb:146:in `eval_input'
        from /usr/local/lib/ruby/1.9/irb.rb:70:in `block in start'
        from /usr/local/lib/ruby/1.9/irb.rb:69:in `catch'
        from /usr/local/lib/ruby/1.9/irb.rb:69:in `start'
        from /usr/local/bin/irb19:13:in `<main>'

がっくり...orz

% ruby19 -v
ruby 1.9.0 (2007-08-26 patchlevel 0) [powerpc-darwin8.10.0]

% [Ruby][雑談] 晴れて新 Fiber も使えるようになったんで、Erlang のプロセスもどきを Fiber で作ってみようと思ったら、多重に resume できない制限に引っかかって挫折した件

ぶっちゃけスケジューラも Fiber 上で動くようにしてしまったのが敗因。 つーか、そういう制限があるの思いっきり忘れてたから激しく悩んだよ。 ほんとはスケジューラはスレッドにしちゃった方が楽にいけたと思うんだけど、なんか Fiber でも大丈夫そうだったからついチャレンジしちゃったんだよね。 無駄な努力だったけども...orz

何はともあれ、今日はもう眠いから終了。

本日のツッコミ(全3件) [ツッコミを入れる]

% きむら(K) [ruby-core 12000 で解決したり?]

% jijixi [ぬおっ、ほんとだ!! ありがとうございます。 つーかこんなの気付かないっすよ(笑 irb(main):001:0>..]

% きむら(K) [いや、わたしもsubscribeはしてますが、あまりまじめには読んでないです(^^; 今回はたまたま記憶に残っていた..]


2007-08-27 [長年日記]

% [雑談] 気温は高いが湿度がわりと低めなので意外にすごしやすい

30 ℃に 50 % といったところ。 体感的には 27 ℃で 70 % よりも楽な感じがする。 やっぱ湿度って重要。

エアコンは『冷房』じゃなく『ドライ』に設定しましょう…とかほんと正しい。 冷房イラネ。(冷房病患者の嘆き)

% [Rails] functional test で使う get とか post とかってメソッドがどこで定義されているか

前にも一回調べたんだけど、どこにあったか忘れてまた調べるハメになったんで、自分用にメモ。 ちなみに Rails の内部では暗黒魔法がたくさん使われているので、

% grep -r 'def get(' *

とかやっても見付かんないからね。

そんでまあ、じらしてもしょうがないのでとっとと発表すると、ActionController::TestProcess.included メソッド内で定義されている。 ファイルで言うと actionpack の lib/action_controller/test_process.rb だね。 このファイルの 350 行目辺り (actionpack-1.13.3 時点) で、class_eval を使って定義されている。 はいはい DRY, DRY :-p

350 %w( get post put delete head ).each do |method|
351   base.class_eval <<-EOV, __FILE__, __LINE__
352     def #{method}(action, parameters = nil, session = nil, flash = nil)
353       @request.env['REQUEST_METHOD'] = "#{method.upcase}" if defined?(@request)
354       process(action, parameters, session, flash)
355     end
356   EOV
357 end

行頭の空白は切り詰めたが、中身自体は単純なコピペ。 今回は、こんなだってわかってたからすぐに探せたけど、最初に調べたときはほんとどうしてやろうかと思ったよ。 英語が苦手な人間としては、わりと「(英語の) チュートリアル読むくらいなら、ソース読んだ方が早いや」などと思ってしまうんだけど、Rails の場合その期待は裏切られることが多い。 あと、なんか知らんけど、実装を書いてるときよりテストを書いてるときの方が何が起きてるかわかんなくなってソースに潜りたくなる事が多い気がするね。 テストを一生懸命書けば書くほど、なぜか中身に詳しくなっていくという(苦笑

本日のツッコミ(全2件) [ツッコミを入れる]

% きむら(K) [> テストを一生懸命書けば書くほど、なぜか中身に詳しくなっていくという(苦笑 ぜひ Yet Another RHG ..]

% jijixi [さすがにそこまでは、どうかと(苦笑]


2007-08-29 [長年日記]

% [Rails] before_filter の動きって怪しくね?

なんか複数の filter を指定してるときって何か微妙。 とりあえず、マニュアル (ActionController::Filter::ClassMethods) の Filter Chain Halting に書いてある…

Simply return false from the filter or call render or redirect.

を読むかぎり、filter が false を返すか、render か redirect_to (…の誤植だよね?) を呼ぶと以降の filter は処理されない…というように思えるんだけど、どうもウソっぽい。

いまいち動きを掴みきれてないんだけど、いろいろ実験した感じだと false を返さない限りは問答無用で残りの filter も実行されてるっぽい。 じゃあ、render か redirect_to を呼んだら…というのは filter 内のことじゃなく action 内でのことなのか?と思って、after_filter を設定して action 内で render とか呼んでみたけど、やっぱりその after_filter は実行されてるみたい。 何なんだろね?

まあ、ともあれ、filter 内で redirect_to とか使うときは、ちゃんと一緒に false を返しておこうね、という話かと。

でも、なんか after_filter だと false を返しても残りが実行されてるような気もして、さらに微妙なんだよな。 (うまく実験する方法がわかんなくて、はっきりしないんだけど……)

% [clip][雑談] オブジェクトファイルシステム (db4oとトランペット日記)

日々の破片経由で。

ファイルシステム自体が基本的なオブジェクトを格納する、オブジェクトファイルシステムであったらいいじゃないかと思うわけです。オブジェクトファイルシステムの1つの形が通常のファイルシステム、という逆転の発想で。

TAD の時代到来ですか? とか思った。

まあ、TAD にはあまり優れた実装は存在しないので (B-right/V のは、お世事にも高パフォーマンスとは言えないだろう)、誰かがそういうのを作らない限りはそんな時代は来ないと思うが。 T-Engine 方面に BTRON の要素を取り込むような話もあったから、もしかしたらそっちで何か動きがあったりするのかもしれないが、残念ながら最近その辺まったく調べてないのでわからん。 それから、db4o さん (で良いのかな?) が想像しているものと、TAD は全く違うものである可能性はあるので、その点はあらかじめことわっておく。


2007-08-30 [長年日記]

% [Ruby][Rails][雑談] 関数的メソッドの呼び出し時にはカッコを省略しないようにしよう

……と思っている。 いつかそのコードを読む誰かのために。 あるいは忘れた頃にそのコードを読む自分のために。

まあ、引数があるメソッドならカッコを省略しても良いと思うけど、無引数のメソッドを関数的に呼ぶ場合はカッコを付けないと、ローカル変数なのかメソッドなのかパッと見、区別が付かない。 区別が付かないから、やたらと余計なところまで読むはめになる。 嬉しくない。

Rails のソースを読んでると、かなりこういうケースがあって、しかも private 指定されたメソッドだけじゃなく、自分自身の public なメソッドもそういう風に呼んでたりするから、とにかく初見の識別子を見つけたら、それがローカル変数なのかどうか確かめるために、無駄に人間構文解析をしなきゃならない。 しまいにゃ attr_accessor とかが設定されてるインスタンス変数まで、関数的メソッドのように呼んでたりするからブチ切れそうになる。 アットマーク一つすら書くの面倒かよ。

こういう目に遭うと、ちょっと Python が恋しくなる。 いつも self が必要なのも、いつも関数呼び出しにカッコが必要なのも冗長ではあるけど、見方によっては幸せに繋ってたりするんだなあ。 まあ、書き手のための利便性と読み手のための利便性のバランスってのは難しいもんだけど……

% [独り言] ぐおぉービール飲みてー

つーかギネスのサイトの写真がうまそうすぎる。

よし、買ってこよう。 ってか、ギネスってコンビニとかで売ってたっけ?

% [雑談] 某ニコなんとかの某らきすた MAD のコメが楽しい件

某ニコなんとかのアカウントがある人は、「らぶ☆ちと」で検索。 MAD 自体もよくできてるんだけど、それ以上にみんなのツンデレコメントが笑えるっすよ。

70回見たが中毒性皆無だな

とか

は?クソ動画はさっさと削除されろやww 15回見てもつまらんww

とか、愛が溢れてますw

本日のツッコミ(全2件) [ツッコミを入れる]

% みずしま [動機は違いますが、First Steps to Scala: http://www.artima.com/scala..]

% jijixi [ふむふむ、そういうのもアリか。 どっちにしても、「省略できるから省略する」みたいな短絡思考じゃなく、どっちでも書ける..]


2007-08-31 [長年日記]

% [Ruby][雑談] やっぱそういうところのバランス感覚は難しいなと思う

arton さんに言及されているようなので。

面倒かどうかではなく、常にフックを入れることを念頭におけばそういうコードになるはずだ。

というのには同意します。 まあ、あそこでグチってたのは単にローカル変数なのか関数呼び出しなのか区別が付かなくて、読むのが面倒だってことを、あまり深く考えずに書き殴っただけなので。 補足をするなら、アクセサを通すのが妥当だという状況なのだとしても、読むときの事を考えれば、

self.hoge

とか

hoge()

とか書いておけば、後で見てわかりやすいだろう…くらいの話です。 まあ、書く側から見れば面倒極まりないですが。

ともあれ、アクセサを通す通さないの判断にしても、書き方の問題にしても、バランスの取り方は難しいなと思うわけで、なかなかはっきりと『こうすべき』みたいな一家言を持つには至りませんね。 日々模索中。

ついでなんで、keisuken さんの方の話にもひとこと。

DSL として構築された上でそう書くのはもちろん問題無いでしょう。 つまり、Rails でアプリケーションを作る人がそう書くのは、別に悪くはないと思います。 flash とか session とか触るのに、いちいち flash() なんて書くのはアホみたい。

ただ、DSL "を" 構築している部分 (要は内部的な部分) では、やっぱり読み易さも考えて欲しいなあと思ってしまいますね。 特に Rails なんかは、ただでさえ暗黒魔法のオンパレードで読みづらいったらないので、せめてできるかぎりの可読性を持たせて欲しいと(苦笑


トップ 最新 追記

日記ってのは本来、自分で読み返すためにあるもんだよなあ……
もしくは有名人になったら死後に本になったりとかか?

RSS はこちら

jijixi at azito.com