2005/06/30

今年栽培している唐辛子は、やたらにでかい。奥様は、実はこれはシシトウだと言い張ってるけど、スーパーで売ってる並のシシトウよりでかい。で、唐辛子の種類をいろいろ調べたら、でかいのもあるらしい。きっといまに赤くなるに違いない。ところでピーマンって、フランス語の唐辛子(piment)が語源だったのね。
Joelさんの「ハンガリアン表記を見直そうぜ」というコラム。
Joel on Software : Making Wrong Code Look Wrong

えらく誤解されてるような気がするけど、最後まで読むと、要するにこういう主張でしょ?

  • 変数や関数には一貫した意味のわかる名前を付けようね

  • 一行ずつ目でバグをつぶせるから(本来の)ハンガリアン記法は意外にお勧め

ハンガリアン記法にまつわる憎悪はひどいから、この主張は rant にしたって誤解されやすいよ。本人も確信犯だと思うけど。まあ、個人的にはハンガリアン記法にうらみもないし、プロのコーダでもないから、その宗教論争はとくにどうでもいいや。

むしろ、彼がハンガリアン記法を持ち出してきた理由付けがちょっといけてると思った。つまり、ここではコーディングスタイルが対象なんだけど、人間の認識力が何か対象に意味を見出せるようになるには没入経験が必要ってとこ(ところで多分に鹿野による拡大解釈が入っているから本文を読んだほうがいいと思う)。彼のパン工場のバイト経験もそうだけど、何でも最初に接したときには混沌であることしか認識できない。とにかく混沌を相手にもがいているうちに、そのうち認識が意味を持つようになる。認識のフィルタができるとも言える。プログラミング言語だけでなく、自然言語はもちろん人間関係でも同じ。で、Joelさんのノリは、そうやって認識できるようになったら(モノホンの)ハンガリアン記法がけっこういけるんだよ、というように読める。クサヤとかフナズシが癖になるのと似てるかも。それじゃあだめだよどんな人でも読みやすいコードにしなけりゃっていう反論はあり得る。ただし、Joelさん自身が「読めねー奴はどうやったて読めねーから論外」という言い方もしている?ので、やっぱりこれは rant なんだろう。

2005/06/28

労働が限界生産力と限界不効用の均衡だけで決定する時代がうらやましい。って、最近こんな愚痴ばっかり。労働者である自分の限界不効用は超過してるし、企業が自分に求める限界生産力は超えていると思うけど、もはやいずれも実質賃金とかけ離れている。
要するに、ここのところ感じているのは年収の問題だということに気がついた。しかも、今後年収が増加する希望もない(これは業界の問題というより弊社の問題)。
これまでもうすうす気が付いてたけど、先月からいろいろあって、はっきりした。ひとつには父親の死がある。生涯にわたって年収300万円で幸せなのは、あくまでも不測の事態が起こらない世界の話だ。こう書くと、不測の事態に備えるために保険に入りましょうって言われる。長谷川京子や矢田亜紀子はかわいいけど、生命保険は勘弁してください。保険は年収300万円の労働者にやさしいとはいえない。社会保険も不公平の塊だし。いずれにしたって、むー。
コドモが生まれたらどうするか、というのも、同じ意味で年収300万円にやさしくない不測の事態だと思う。要するに、自分以外の身内(この場合は奥様と生まれてくるコドモ)に生じる不測の事態を乗り切るには、どうあがいたって現金がいる。
これら(自分以外の身内に起こる不足の事態)に比べれば、あとはマイナーな問題。人生を豊かに暮らすためには資金が必要なんだとか、自分は現金が欲しいんじゃない正当な評価が欲しいだけなんだとか、老後の安泰だとか、生きる意味だとか。
こうなったら業務時間中にデイトレーディングにいそしむか、それとも、もっとストレートに副業をするか。でもそんな余裕はないのです。

2005/06/27

アジアンランチ 。ずいぶん前から会社の近くに車が止まるようになって、気になってた。いつも行列で、しかも並んでるのが女の子ちゃんばっかりだったので、むしろネガティブに気になってたんだけどね。女の子ちゃん向けのジャンクフードはカドが取れたやつが多い。雰囲気だけのアジア料理は勘弁ならなくて、むしろ徹底的にジャンクなものを食わせてほしいんですが。
で、このアジアンランチは良心的だと思った。ご飯が日本人好きするベタベタであることを除けば、カレーや炒め物は最低限のジャパナイズに抑えてあるように思う。にしても、粘着な米が好きな日本人って多いよなあ。僕はササニシキが好きだったんだけど、ササニシキってすでに入手困難な希少種じゃない? スーパーに置いてある玄米はコシヒカリとあきたこまちだけ。まあ、あきたこまちはおいしいからいいけど。ところで我が家で炊く米が100%玄米なのは、単にそのほうが旨いからであって、健康志向とは何の関係もありません。

ところで、親がコシヒカリばっかり有り難がって食わせるから、オトナより種族としてブランド志向が強いコドモらはしょーもない発想をするようになるらしい。

なんで、お米を全部有名な「コシヒカリ」とかにしないの?

Ans. それは、コシヒカリが好きじゃない人もいるからです。

2005/06/25

今月の初めに八ヶ岳に登ったんだった。
ツクモソウが咲いているのは珍しいらしい。
いや、別に攻めているわけでも否定しているわけでもなくて、人様から金銭をいただくということの重みを痛感してもらいたいだけなんです。

2005/06/23

昨日早く帰って何となくテレビを見ていたら、サラリーマンの給与所得の平均が440万円というデータが紹介されていた。で、今日は住民税の超過分を支払いに郵便局に行って、長い待ち時間を自分の所得明細を眺めながら過ごしてたわけですよ。マーマーマーマーお金がない♪
なきそうになった。冷静に考えると平均の80%にも届いてない。さすがは斜陽産業。

  • 自分の意思で始めた個々のプロジェクトは面白いし、心身ともに糧になっている。たぶん社会的意義もある

  • 業界/会社の収益構造が崩壊しているので、あきれるくらい頭の悪そうな仕事も襲い掛かってくる。しかもその仕事は社会や地球環境にとって悪。決定的に


これで儲かってれば、まだジレンマを無視してでも働けそうなんだけどなあ。でも実際にはそうじゃない。前の会社を辞めたのも似たようなジレンマだったっけ。給料は圧倒的によかったけど、あの会社には心底付き合いきれないと思った。結局ジレンマで辞めたんじゃなく、ジレンマが崩れて辞めたってことか。

ところで「マーマーマーマーお金がない」は kin-dza-dza に出てきた唱だと信じてたんだけど、この映画を見た人の誰もがそんな唱はなかったと言って冷たい目で見るのはなぜだろう。

2005/06/20

いっかい掴みかけた継続引き渡しの概念を失いそうだったので脳内を保守。お題は、"A Gentle Introduction to Haskell" で紹介されている Haskell の quicksort を Scheme に移して、さらに末尾再帰に書き直すこと。そもそもの Haskell のコードはこれ。

quicksort [] = []
quicksort (x:xs) = quicksort [y | y <- xs, y<x ]
++ [x]
++ quicksort [y | y <- xs, y>=x]

まずは同じものをSchemeで。

(define (quicksort ls)
(if (null? ls)
'()
(append (quicksort (filter (lambda (x) (> (car ls) x)) (cdr ls)))
(list (car ls))
(quicksort (filter (lambda (x) (<= (car ls) x)) (cdr ls))))))

Haskell の表記に比べると filter とか出てくる辺りが痒い。けど仕方ない。とにかくこれを末尾再帰にしてみる。

(define (quicksort/cps ls k)
(if (null? ls)
(k '())
(quicksort/cps (filter (lambda (x) (> (car ls) x)) (cdr ls))
(lambda (ls-lower)
(quicksort/cps (filter (lambda (x) (<= (car ls) x)) (cdr ls))
(lambda (ls-upper) (k (append ls-lower (list (car ls)) ls-upper))))))))

Haskell では継続を安直に捕まえられないのだろうか?
やっぱり集合を扱う際には最初の Haskell のコードが一番しっくりくる。集合論のノリで問題を解きたい場合は Haskell の考え方のほうが扱いやすいのかもしれない。Scheme でも Haskell チックに集合を定義できるマクロを用意すれば同じなのかな。でも、可算無限集合が出てくるたびに delay で関数を定義し直すのはいやだな。

2005/06/17

所用で早く帰ったところ奥様が夕ご飯を食べていないというので、日暮里の吉野屋に入った。あいかわらずこの店はレベルが高い。味もそうだけど、店員のレベルも高い。僕はいつも七味唐辛子を振る際に容器のネジ蓋をはずして使うんだけど(そのままだと口が小さくてたくさん出ないから)、今日は手がすべって蓋を味噌汁の中に落してしまった。そんなイリーガルな使い方をしている自分のほうが悪いのに、「火傷とかしてませんか」といって手際良く蓋を回収してくれる。プロだね。支払のときも、980円の会計に300円の株主優待券を4枚出したら、「優待券はおつりが出ないから」といって、ちゃんと1枚を戻してくる。「万札しかないから4枚払いますよ」といっても、笑顔で奥に行って9920円の釣銭を用意してきてくれる。味噌汁こぼした客が優待券で会計するという時点で店によってはいやな顔をするだろうし、吉野屋は万札を受け取ると必ず奥に持って行かなければならないので、そもそも万札を出す客自体が面倒なはずだ(しかも80円の支払に万札!)。ただでさえ夕食どきで忙しいってのに。
こういう店がある限り、この会社に投資して正解だと思う。そして吉野屋さん、素晴らしい接客をしてくれた日暮里店Mさんの時給を上げてあげてください。
長方形が重なるかどうかの問題(参照)。数式は陰気臭いからコードにしろという圧力があったのでがんばった。結局、3時間以上かかった。ほとんどの時間を長方形の表現に悩んだ気がする。で、まあ自然数の直交グリッドに沿ったものだけでいいじゃんということにして、あきらめました。有理数の直交グリッド(つまりコンピュータディスプレイ)までなら同じノリで解決できると信じる。だって定積分ってそういうノリだし(ようは言い訳)。でも、一般のHausdorff空間で解決しろといわれているわけでもないし、そもそも長方形が定義できない空間じゃ意味ないしね。

(use srfi-1)

;; 長方形は対角線の端点(にあるマス)で定義: ((x0 y0) (x1 y1))
;; ただし、 右上がりの対角線で定義 i.e. x0 <= x1, y0 <= y1
(define-syntax rect?
(syntax-rules ()
((_ rect ...)
(and (and (<= (caar rect) (caadr rect)) (<= (cadar rect) (cadadr rect))) ...))))

(define (expand-x from-ls to-ls)
(let ((xfrom (car from-ls)) (xto (car to-ls)) (yfrom (cadr from-ls)))
(map (lambda (x) (cons x yfrom))
(let f ((xcurrent xfrom))
(let ((xnext (+ xcurrent 1)))
(if (> xnext (+ xto 1))
'()
(cons xcurrent (f xnext))))))))

(define (expand-rect-diag from-ls to-ls)
(let ((x-ls (expand-x from-ls to-ls)) (yfrom (cadr from-ls)) (yto (cadr to-ls)))
(let* ((ycurrent yfrom) (ynext (+ ycurrent 1)))
(if (> ynext (+ yto 1))
'()
(append x-ls
(expand-rect-diag (list (car from-ls) ynext) to-ls))))))

(define (expand-rect rect-with-diag)
(let ((from-ls (car rect-with-diag)) (to-ls (cadr rect-with-diag)))
(expand-rect-diag from-ls to-ls)))

;; 長方形からなる領域の面積(=マスの数)
(define-syntax sumup-rect
(syntax-rules ()
((_ e1) (length (expand-rect e1)))
((_ e1 e2 ...)
(length (lset-union equal? (expand-rect e1) (expand-rect e2) ...)))))

;; 2つの長方形が交わってるかどうか
(define (intersect? rect1 rect2)
(if (rect? rect1 rect2)
(< (sumup-rect rect1 rect2) (+ (sumup-rect rect1) (sumup-rect rect2)))))

できたかな?

(define rect1 (list '(0 0) '(3 2)))
(define rect2 (list '(3 3) '(4 4)))
(define rect3 (list '(1 1) '(4 4)))

gosh-rl> (intersect? rect1 rect2)
#f
gosh-rl> (intersect? rect1 rect3)
#t

そうそう。ようやく Gauche-readline の存在を知りました。画期的です。横田さん、ありがとうございます。

2005/06/14

hisashim さんが 長方形Aと長方形Bが一部でも重なるかどうかを判断する条件式 挑戦してた 。数式なら5分でいいよ。コードに落とすには1時間以上かかると思う(あくまでも自分のスキルの限界)。

長方形A, Bの面積を|A|, |B|とする。

|S| =def(x,y) {(x, y) ∈ A ∪ B} dxdy

|S| < |A| + |B| ⇒ A と Bは交わる

位相をかじったことがある学生ならこういう思考になりそう。ちなみに上記の判定式では、AとBがぴったり接触している場合を「交わらない」と見なしている。

2005/06/12

ちょうしにのって、何年か前にシベリアのバイカル湖で撮ったスナップもスキャニングしてみた。これは OLYMPUS PEN F + E Zuiko 38mm F2.8(いわゆるパンケーキ)で、TRY-X。ネガはきずきずだったので、ちょこっと修正。あとは Web 用に解像度を下げている。
2001_lake_vical_small 2001_lake_vical_kamome_smal

2005/06/11

わけあってスキャナー(EPSON GT-X800)を購入した。フラットヘッドなのに4800dpiで35mmのポジフィルムがスキャニングできる。そこで、昔とったポジを取り込んでみた。そのままだと150MバイトあってFlickr!に上げられないので横800ピクセルまで圧縮しているけど、それ以外の画像処理はとくにしていない。

fuji_from_takanosu_small

前景の山脈の尾根から滲む空気感。やっぱりポジフィルムって圧倒的に情報量が多いのね。ちなみにこのときの撮影機材は、PENTAX SPF + MC FRECTAGON 35mm だったと思う。

2005/06/10

結局、遅延評価バージョンを書いてみた。

; lcar, lcdr, ltake は "Gauche リファレンスマニュアル" の例を流用
; http://www.shiro.dreamhost.com/scheme/gauche/man/gauche-refj_90.html#SEC94
(use srfi-1)

(define (lcar lis) ;; lazy car
(car (force lis)))

(define (lcdr lis) ;; lazy cdr
(cdr (force lis)))

(define (ltake lis n) ;; lazy take
(if (<= n 0) '() (cons (lcar lis) (ltake (lcdr lis) (- n 1)))))

(define (lfilter pred ls) ;; lazy filter. i know it's not cps.
(if (pred (lcar ls))
(cons (lcar ls) (delay (lfilter pred (lcdr ls))))
(lfilter pred (lcdr ls))))

(define (integers-above num)
(let mkls ((x num))
(delay (cons x (mkls (+ x 1))))))

(define primes
(let prime-list ((ls (integers-above 2)))
(cons (lcar ls)
(delay (prime-list (lfilter (lambda (x) (> (modulo x (lcar ls)) 0)) (lcdr ls)))))))

gosh> (ltake primes 25)
(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)

お膳立てが多いけど、primes プロシージャに関しては Haskell バージョンと同等になったと思う。

2005/06/09

情報処理学会誌2005年4月号の『関数プログラミングの妙味』(PDF)という記事を読んでいたら、素数を求めるこんな Haskell スクリプトが紹介されていた。

primes = sieve [2..]
where sieve (s:ss) = s:sieve (filter (\x -> x `mod` s > 0) ss)

Main> take 25 pimes
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]

日本語はおかしな和田さんだけど、これはなんだかかっこいい。Scheme でも同じことがしたい。

(let prime-list ((ls '(2 3 4 5 6 7 8 9 10 11 12)))
(if (null? ls)
()
(cons (car ls)
(prime-list (filter (lambda (x) (> (modulo x (car ls)) 0))
(cdr ls))))))

=>(2 3 5 7 11)

遅延評価が当たり前の Haskell と違って無限リストを自然に扱えないのがつらいところ。というわけで delay を使ってみる。とりあえず自然数全体の集合(リスト)はこんな感じかな。

(define int-inf
(let mkls ((x 0))
(delay (cons x (mkls (+ x 1))))))

『Gauche リファレンスマニュアル』の遅延評価の例にある "ltake" を使わせてもらえば、ゼロから始まる任意の長さの自然数列が得られる。

gosh> (ltake int-inf 20)
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)

でも、これを最初の prime-list に組み込むのはめんどくさいな。そもそも、自然数列を得るだけなら遅延評価を使わなくてもいいような気がしてきた。というわけで

(define (primes-under num)
(let prime-list ((ls (let mkls ((x 2))
(if (<= num x) '() (cons x (mkls (+ x 1)))))))
(if (null? ls)
()
(cons (car ls)
(prime-list (filter (lambda (x) (> (modulo x (car ls)) 0))
(cdr ls)))))))

=>(primes-under 100)
(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)

うーむ。かっこよさとしてはちゅうくらいか。遅延評価のサポート具合もプログラムの抽象化に大きく影響するらしい。

2005/06/07

再び、HTMLをプレビュー目的だけに使うときの姑息なテクニックをはっけん。
今回は、img タグで埋め込んだ図が印刷したときにページで分断されてしまう問題を回避したい。CSS 2.0では page-break-inside:avoid というプロパティも用意されているんだけど、Firefox ではサポートされていないっぽい。少なくとも有効にならない。page-break-after:always は利くのにね。

<table><tr><td><img src="./fig/foobar.gif"/></td></tr></table>

ようするにtableのセル内では改ページされないみたい。

1年後にこのエントリを見て、あの頃は若かったなと恥じること。

2005/06/06

「優秀な人たちはどこかでつながってる」は、僕らの生活している世界をモデルにすると証明可能な命題に思える。この命題の対偶を取ると、「どこでもつながっていない人たちは優秀ではない」。つまり、最初の命題が正しいと仮定すると、ヒッキーは優秀ではない。そうだったのか……

2005/06/02

すばらしい。実のところ、折曲げポイントをどうやって見定めればいいのか、こっそり悩んでいたところ。スパイラルはだんだん小さくなっていくのがきれいなので、まず文字列を逆転させてから2〜10文字くらいの範囲で一番小さなループ(8文字で構成されるもの)が描けるか調べ、描けなかったらちょっとループを大きくして再挑戦し、描けたらその地点からもうちょっと大きなループに挑戦し……という戦略を妄想していたんだけど、最初に全探索で候補を探してから「きれいさ」に適ったものを見付けるという発想はまったくできませんでした。ある意味、富豪的プログラミング