2005/07/29

ある人が『好きな言葉は四文字熟語』というとき、その人が本当に四文字熟語が好きだとすると、四文字熟語は四文字熟語ではないから、実は四文字熟語が好きではない。一方、四文字熟語が好きではないとすると、四文字熟語は四文字熟語でないから、やっぱり四文字熟語が好き(ハイチュウ率)。この『四文字熟語のパラドクス』は、命題中の「四文字熟語」を「四字熟語」に言い換えると解決する。しねえよ。基礎論すっかり忘れちゃったなあ。蒸しあついなあ。ウナギ食べたい。

2005/07/28

いまさら気が付いたしょうもないこと。Scheme と Haskell では fold の動作が違うんですね……
どちらもこんな風に書くわけだけど(Haskellの場合は foldl)、

fold proc 種 (x_1 x_2 ... x_n)

これが Scheme では

proc (x_n ... (proc x_1 種)...)

と評価されるのに対し、Haskell では

proc (...(proc 種 x_1) ... x_n)

とみなされる。

「種とリストの要素のどちらを先に proc に渡すか」が正反対なので、除算みたいな可逆でない演算の場合に思い悩む。

gosh-rl> (fold / 128 '(8 4 2))
0.03125

Hugs.Base> foldl (/) 128 [8,4,2]
2.0

この例では Haskell のほうが感覚にマッチするなあ。Scheme で Haskell と同じことがしたい場合には無名関数を使うしかないのかしらん。

gosh-rl> (fold (lambda (x y) (/ y x)) 128 '(8 4 2))
2


なんでこんなことが気になったかというと、情報処理学会誌6月号の Haskell の数当てゲームの記事に、0~9 の自然数からなるリストを各数字が各桁に対応する1つの自然数に移す関数 pack: (a b c ..) → abc.. が foldl で実装されていたから。こんなやつ。

Hugs.Base> foldl (\ x y -> 10 * x + y) 0 [1,2,3]
123

上記のような理由で、これをそのまま Scheme に置き換えても期待した結果は得られない。

gosh-rl> (fold (lambda (x y) (+ (* 10 x) y)) 0 '(1 2 3))
60

lambda 内の x と y を逆にすればいいだけなんだけどさ。

2005/07/26

会社のDebianサーバがいかれて復旧で一日が終わってしまった。せっかく台風なのに。それにつけても本業がちっとも進まないのはなぜだろう?

2005/07/25

台風がくるというので定時に帰宅してみた。そしたら、きた。それにしても汚い屋根だ。
まったく関係ないけど、先々週に東北地方を車で廻ったときに撮ったストーンサークルの写真をいつの間にか自分でFlickr!に上げていたみたい。

2005/07/19

依然として調子が悪いな。目をつぶると意識は鮮明なんだけど、目を開けていると倒れそう。というわけで、早いけど帰宅して寝る。

2005/07/18

三河島駅前に「若松」という居酒屋がある。毎日のように店の前を通るたび、やきとりと鰻の香にため息をついてきた。なんとなく入る機会もなく、この地に移り住んで5年目、今日初めて店に入ってみた。
店内は休日の18:00すぎだというのにすでに満員状態。かろうじて空いた6人がけの座敷に相席で、念願のやきとりやら鰻やらを注文した。5年間毎日予想してきたとおり、焼がうまい。とりたてて高価な素材をつかっているわけではないのに、焼の上手さで何を頼んでも期待をうらぎらない。しかも安い。
こういう居酒屋が目の前にあるのは素晴らしいことだけど、いかんせん奥様としか利用する機会が持てないのが残念なところ。このあいだも、ちかぢか結婚する友人が東東京に越したいと言ったところ、相手に強行に反対されたらしい。東東京は恐いんだって。むべなるかな。きょうび東京の西のほうが文化的だと思われてるからな。しかし、自分の偏見では、東京は東のほうにこそ文化がかたまっていると思うんだけどなあ。
くそ暑いので献血センターですずやかに読書でもしようと思ったら、血小板を200ml抜いたところで貧血を起こしてしまった。看護婦さんが3人で処置してくれたのですぐに回復したけど、手は痺れるし、意識はふらつくし、早めに気持ちが悪いと申告してよかった。看護婦さんの話しを統合すると、どうやら暑さで脱水ぎみになったらしい。あと、個人的には、最近あんまり肉々しいものを食べてないことも理由のひとつだと思う。そこで、とりあえず帰りがけに吉野屋で牛焼肉丼。

2005/07/15

スターウォーズ エピソード3を見にいったら、コルサント→モンテカルロみたいな連想が働いてしまって、長方形が重なるかどうかを面積の差で解決する問題(参照)ってモンテカルロで解けるじゃん。

(use gauche.uvector)
(use srfi-27)
(use math.mt-random)

;; make random vector
(define (make-random-vector! n)
(mt-random-fill-f64vector! (make-random-source) (make-f64vector n)))

(define (ith-random randoms i)
(f64vector-ref randoms i))

(define (ith-random-pair randoms i)
(list (ith-random randoms (* 2 i))
(ith-random randoms (+ (* 2 i) 1))))

;; rect as ((x0 x1) (y0 y1))
(define (point-inner-closed? point closed)
(and (< (car closed) point) (< point (cadr closed))))

(define (pair-inner-rects? pair rects) ; not cps !
(let ((rect (car rects)))
(if (null? (cdr rects))
(and (point-inner-closed? (car pair) (car rect))
(point-inner-closed? (cadr pair) (cadr rect)))
(or (pair-inner-rects? pair (list rect))
(pair-inner-rects? pair (cdr rects))))))

;; monte-carlo
;; area as '(rect1 rect2 ...)
(define (monte-carlo area n)
(let ((randoms (make-random-vector! (* 2 (+ n 1)))))
(let f ((i 0))
(if (> i n)
0
(if (pair-inner-rects? (ith-random-pair randoms i) area)
(+ (f (+ i 1)) 1)
(f (+ i 1)))))))

;; main
(define times 10000)
(define rect1 (list (list 0.0 0.2) (list 0.0 0.2)))
(define rect2 (list (list 0.1 0.3) (list 0.1 0.3)))

(define s1 (monte-carlo (list rect1) times))
(define s2 (monte-carlo (list rect2) times))
(define s1-and-s2 (monte-carlo (list rect1 rect2) times))

(display (< s1-and-s2 (+ s1 s2)))

=> #t

これなら長方形を実数で指定できる! ハエを殺すのに焼夷弾を持ち出すみたいな話だってのはわかってますって。

2005/07/07

Haskell と継続について。いただいたコメントによるとモナドで継続を実現できるんですね。Haskellのコードで理解するのはつらいので、ここを読み返してみた。

f: x→y により実行される計算の継続は、f': x→((y→k)→k) となるような f': x→M(y) と見なせる。ここで M はモナド則を満たす。という理解でいいのかな。

にしても、これがHaskellのプログラミングで意味があるのかどうかは、あいかわらずよくわからない。実際に Haskell でプログラミングしているわけじゃないので、わからなくて当然といえばそれまでなんだけど、応用を生み出す妄想力の欠如を我ながら痛感するところ。ところで、あちこちで「Haskell では遅延評価があるから無理に継続引き渡しにしなくてもいい」って言及されているのは、まるで継続と遅延評価とが同じ概念の2つの表現みたいに読めてしまうから、いけないと思う。実際には、評価の順番が問題視されなければ継続引き渡しで処理が最適化されるわけじゃないってだけのことだと思うんだけど、僕のほうが勘違い?

2005/07/06

だらだらとWebを見ながら、howm形式でばしばしメモるためのBookmarklet。Firefox1.0.4でのみ動作を確認。改行が便宜的なものであるのはいわずもがな。

javascript:
var pageTitle=document.title;
var pageURL=document.URL;
var userSelection=document.getSelection();
function nomdic(cc){if(cc<10){cc='0'+cc};return cc};
var nowDate=new Date();
var yyyy=nowDate.getFullYear();
var mm=(nowDate.getMonth()+1);
var dd=nowDate.getDate();
var hh=nowDate.getHours();
var min=nowDate.getMinutes();
var ss=nowDate.getSeconds();
var howmName=yyyy+'-'+nomdic(mm)+'-'+nomdic(dd)+'-'+nomdic(hh)+nomdic(min)+nomdic(ss)+'.howm';
var howmDate=yyyy+'-'+nomdic(mm)+'-'+nomdic(dd);
var openWin=window.open('',howmName,'innerWidth=600,innerHeight=400,scrollbars,menubar');
openWin.document.writeln
(howmName + '<br/>= ' + 'URLメモ ' + pageTitle + '<br/>' + '['+howmDate+']' + ' &lt;&lt;&lt; '
+ pageURL + '<br/><br/>' + userSelection); void(openWin.document.close());

本当は、$HOME/howm/以下へ自動的に吐き出したいんだけど、javascriptだけでは無理で、XPCOMを使うしかないっぽい。それにしてもこういうのを書くと生気を吸われるきもち。

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 の存在を知りました。画期的です。横田さん、ありがとうございます。