メッセージ。 - diary

2006-03-19

# Momokaのソースコード、お見せするの恥ずかしいですけど

昨日、hirofummyさんが興味を示してくださったので、現状のMomokaのソースコードを公開します。http://nnri.dip.jp/~yf/source/Momoka-0.36.tar.gzhttp://nnri.dip.jp/~yf/source/Momoka-0.35.tar.gz(えーと。まともそうなほうを持ってってくださいm(_ _)m)

一応動くコードなんですが、データがない状態ではテストしてないので、たぶんまだインストールしてもうまく動かないです。コード眺め用ということで、お願いします。あと、main関数に近いところを中心に、コードが汚ないのもご容赦を。動きがありそうなところは、あとでリファクタリングするつもりでした。

パーサ部分はこんな感じです。けっこう手抜きです。

(define-module momoka.kcdp3
  (use srfi-13)  ;; string-prefix?
  (use text.html-lite)
  (export text->kcdp kcdp->html kcdp->text kcdp->t))

(select-module momoka.kcdp3)

(define (with-lines lines proc)
  (string-join (map proc lines) ""))

(define (div istring divider)
  (map (lambda (e) (string-trim-both e)) (string-split istring divider)))

(define (getlines lines pattern)
  (let1 plen (string-length pattern)
    (let loop ((lines lines) (out '()))
      (if (null? lines)
          (values (reverse out) lines)
          (if (string-prefix? pattern (car lines))
              (loop (cdr lines) (cons (string-drop (car lines) plen) out))
              (values (reverse out) lines))))))

(define (text->kcdp istring)
  (let loop ((lines (string-split istring "\n"))
             (out   '()))
    (if (null? lines)
        (reverse out)
        (let1 line1 (car lines)
          (cond ((string-prefix? "*" line1)
                 (loop (cdr lines)
                       (cons (cons 'caption (string-drop line1 1)) out)))
                ((string-prefix? "-" line1)
                 (receive (lis remain) (getlines lines "-")
                   (loop remain
                         (cons (cons 'list lis) out))))
                ((string-prefix? ">" line1)
                 (receive (lis remain) (getlines lines ">")
                   (loop remain
                         (cons (cons 'quote lis) out))))
                ((string-prefix? "|" line1)
                 (receive (lis remain) (getlines lines "|")
                   (loop remain
                         (cons (cons 'table
                                     (cons "|"
                                           (map (lambda (e) (div e "|")) lis)))
                               out))))
                ((string-prefix? "," line1)
                 (receive (lis remain) (getlines lines ",")
                   (loop remain
                         (cons (cons 'table
                                     (cons ","
                                           (map (lambda (e) (div e ",")) lis)))
                               out))))
                (else (loop (cdr lines) (cons (cons 'plain line1) out))))))))

;; (define ecapt (lambda (e) #`"*,|e|"))
;; (define equot (lambda (e) #`">,|e|"))
;; (define elist (lambda (e)
;;                  (with-lines e (lambda (f) #`",|f|\n"))))
;; (define eelse values)

(define (pp-table obj)
  (define (add-pad istring len)
    (string-append istring (make-string (- len (string-size istring)) #\ )))
  (let* ((div  (car obj))
         (body (cdr obj)))
    (let1 nums
        (let loop ((body body) (nums '()))
          (if (null? body)
              nums
              (loop (cdr body)
                    (let l2 ((record (car body)) (nums nums) (out '()))
                      (cond ((null? record)
                             (reverse (append (reverse nums) out)))
                            ((null? nums)
                             (l2 (cdr record)
                                 nums
                                 (cons (string-size (car record)) out)))
                            (else
                             (l2 (cdr record)
                                 (cdr nums)
                                 (cons (max (string-size (car record))
                                            (car nums))
                                       out))))))))
      (string-join
       (map (lambda (r)
              (string-append
               #`",|div| "
               (string-join
                (let loop ((b r) (nums nums) (out '()))
                  (if (null? b)
                      (reverse out)
                      (loop (cdr b)
                            (cdr nums)
                            (cons (add-pad (car b) (car nums)) out))))
                #`" ,|div| ")))
            body)
       "\n"))))

(define (kcdp->t kcdp . opts)
  (let-keywords* opts ((ecapt :capt  (lambda (e) #`"*,|e|"))
                       (equot :quote (lambda (e)
                                       (with-lines e
                                                   (lambda (f) #`">,|f|"))))
                       (elist :list  (lambda (e)
                                       (with-lines e
                                                   (lambda (f) #`"-,|f|\n"))))
                       (etabl :table (lambda (e) (pp-table e)))
                       (eelse  :else  values))
    (string-join
     (let loop ((kcdp kcdp) (out '()))
       (if (null? kcdp)
           (reverse out)
           (let1 kcdpe (car kcdp)
             (cond ((equal? (car kcdpe) 'caption)
                    (loop (cdr kcdp) (cons (ecapt (cdr kcdpe)) out)))
                   ((equal? (car kcdpe) 'list)
                    (loop (cdr kcdp) (cons (elist (cdr kcdpe)) out)))
                   ((equal? (car kcdpe) 'quote)
                    (loop (cdr kcdp) (cons (equot (cdr kcdpe)) out)))
                   ((equal? (car kcdpe) 'table)
                    (loop (cdr kcdp) (cons (etabl (cdr kcdpe)) out)))
                   (else (loop (cdr kcdp) (cons (eelse (cdr kcdpe)) out)))))))
     "\n")))

(define (kcdp->html kcdp linep)
  (kcdp->t kcdp
           :capt  (lambda (e)
                    (format #f "<h3><span class=\"title\">*~a</span></h3>"
                            (linep e)))
           :list  (lambda (e)
                    (format #f "<ul>~a</ul>"
                            (string-join
                             (map (lambda (f) #`"<li>,(linep f)</li>") e)
                             "\n")))
           :quote (lambda (e)
                    (format #f "<blockquote class=\"quote\">~a</blockquote>"
                            (string-join
                             (map (lambda (f)
                                    #`">,(linep f)") e)
                             "<br />\n")))
           :table (lambda (e)
                    (format
                     #f "<table class=\"wiki-table\">~a</table>"
                     (string-join
                      (cons
                       (format #f "<tr class=\"wiki-tr\">~a</tr>\n"
                               (string-join
                                (map (lambda (f) #`"<th class=\"wiki-th\">,(linep f)</th>")
                                     (cadr e))
                                ""))
                       (map (lambda (line)
                              (format
                               #f "<tr class=\"wiki-tr\">~a</tr>\n"
                               (string-join
                                (map (lambda (f) #`"<td class=\"wiki-td\">,(linep f)</td>")
                                     line)
                                "")))
                            (cddr e)))
                      "")))
           :else  (lambda (e) (format #f "~a<br />" (linep e)))))

(define (kcdp->text kcdp linep)
  (kcdp->t kcdp))

(provide "momoka/kcdp3")
2006-03-19 09:53:50 / ふじさわ / Comment: 1 / Trackback: 0

2006-03-18

# ディレクトリとハイパーリンク

今日はOSC2006に行ってきました。いろんな人とお話しできて楽しかったです。
それで、帰りの電車の中で、shinoさんhirofummyさんと話していたのですが、予想外に面白がってくれたディレクトリとハイパーリンクの話を書いてみます。

たとえばWikiエンジンを作っていると、データ構造をどうしようといつも考えます。Wikiなのだから、ページタイトルとページ本文を対にした構造が基本です。「ラルク アン シエル」といったタイトルと「1996年に結成されたロックバンド」といった本文を、対にして保存するわけです。

しかし、「ラルク アン シエル」の説明は、必ずしも「1996年に結成されたロックバンド」と一意に決まるわけではありません。たとえば最近では、メンバーの一人であるハイドの身長がどうの、という話題でWikipediaの編集合戦が発生しました。つまり、誰かが思う「ラルク アン シエル」と、別の人が思う「ラルク アン シエル」は違うわけです。

これは、いろんなものごとに対して当てはまります。たとえば「ビール」は、ある人にとって「すごくおいしい飲み物」ですが、別の人からは「ただの苦い飲み物」です。また別の人から見れば、「当社の主力商品」かもしれません。

なにごとにもいろんな側面があって、見る人や立場が違えば意味が違うわけです。Wikiでもこういったブレを包含できたら、あるいは「ものごとの側面」という情報を利用できればなぁと思います。ちょっと前に、はてなの近藤さんが個人レベルでは「人々の意見は全て正しい」と書いていましたが、こういう感じ。みんなの意見を包含できるシステムにしたい。

そうしたとき、側面という情報が大事だと思うんですよね。どんなものごとも、たくさんの側面を持ちます。ある側面から見たときと、別の側面から見たときで結果が違うのは自然なことです。Wikiのデータ構造にも、この「側面」という情報を持たせたい。「○○さん」から見たときの「ラルク アン シエル」は「1996年に結成されたロックバンド」という感じです。

それで、まぁ少し端折るんですけど、ハイパーリンクはまさにこういう感じだと思うんです。さっき挙げた近藤さんの日記へのリンクで言うと、「このページ」から評価すると、「http://d.hatena.ne.jp/jkondo/20060312/1142098012というリンク先にある文章」は、『個人レベルでは「人々の意見は全て正しい」』として評価(意味を切り取り)できるわけです。

別の言い方をすると、「主語、述語、目的語」で物事を表現するということです。単なるWikiは、述語と目的語しかなかった。主語がなくて、一般化されたものを述語として書くべきとされたわけです。百科事典のようなサイトを作るのにWikiが適しているのはこういう理由です。匿名というのも同じベクトルです。逆にハイパーリンクは、「あるページ」(主語)から、「別のページ」(目的語)を、「リンクアンカーのテキスト」(述語)を用いて表現していく仕組みです。

考えをさらに一歩進めます。ぼくはWebやハイパーリンクを、「すごいなぁ。大ブレークしたし面白いなぁ」と思います。なんでかなぁと考えるわけですよね。ハイパーリンク以前と以降で何が違うのか、ハイパーリンク以前は何があったのか。ハイパーリンクではないものとして、何があるのか。

とりあえず思い付くのは、ディレクトリなんです。ディレクトリは、述語と目的語でものごとを表現する仕組みですね。あるディレクトリにファイルがいくつかあって、それぞれのファイルが「なんのために」そこに存在するかは、表現できない。ディレクトリにはそれを表現する仕組みが備わっていません。

収集がつかなくなってきたので、とりあえずまとめます。
- 述語と目的語でなにかを表現する仕組み:ディレクトリ、従来のWiki
- 主語、述語、目的語でなにかを表現する仕組み:ハイパーリンク、ぼくが作りたいと思っていたWiki

YASWiki2ではこういうことをやろうとしていましたし、その前のYASWikiもこの問題を意識していました。Momokaのマーク機能もその延長線上にあります。桶さんがTumikiで実装している2つのキーでページを指定する機能も、たろうさんがProfListで実現している人と属性でなにかを表現する機能も、いろいろ狙っているでしょうけど、同じ問題を意識しているのだろうと考えています。

まぁ、単にこんなこと考えてますということで。なんの話からこんなことになったんでしたっけ?
2006-03-18 23:23:14 / ふじさわ / Comment: 1 / Trackback: 0

# 「防衛庁の公務PC、私物が半数、警察は4割」

ウィニー問題:防衛庁の公務PC、私物が半数、警察は4割−今日の話題:MSN毎日インタラクティブ

そりゃそうだろうなぁと思う。官公庁に限らず、こういうことはいろんなところで行われているはず。ただし、ぼくはそれが悪いとは思わない。公私は混ざるものと考えるからだ。警察官になる人は、警察官になりたいから、あるいはそこでやりたいことがあったからなったはず。それを消しさることはできない。単なる歯車として、部品として便利に使うことはできない。

業務効率を高めるため、コンピュータの勉強をする人がいる。経済を勉強する人がいる。新聞をとることだって、社会を学ぶ効果がある。それらに経費は支払われない。そうして身につく能力、知識は、個人に属するものだからだ。逆に企業や組織が、そういったことを学ばせようとしてもうまくいかない。組織は歯車や部品で成り立つのではない。

人間は工業製品でない。もっとやわらかくて、変わりやすくて、デリケートで、相性の問題を持つ、しかし潜在的なエネルギーを秘めた、文字どおり有機的なリソースだ。そこから何かの機能だけを取り出すことはできない。いろいろな機能とエネルギーを、混ざったまま扱わねばならないし、それでいいとぼくは思う。
2006-03-18 10:58:25 / ふじさわ / Comment: 0 / Trackback: 0

2006-03-17

# ぼくはじぶんのあたまがおかしくなったのかとおもいました

はてなブックマーク - ステータス200なのに「その商品はありません」

きょうぼくは、はてなブックマークをよんで、「これはおかしい」と思うぶんしょうをみつけました。それなのにみんなは、「さんこうになる」とか「べんきょうになる」とかいっていて、ぼくは「みんなどうしたんだ。目をさませ!」と思いました。

ぼくはじつは、はてなのあかうんとを持っているので、はてなブックマークはあまりつかったことがないけれども、それでも「みんな目をさませ!」とつたえたかったので、はてなブックマークをつかって「それはおかしいんじゃないの?」とかきました。

でもそれはうまくかけていないような気がしたので、やっぱりもともとの人のブログサイトに、コメントすることにしました。でも、コメントをしたつもりが、ブログにはかいたものが乗りませんでした。ぼくは心ぱいになって、じぶんのにっきページにおなじことをかきました。

でも、ぼくのいうことはだれもきいてくれませんでした。ぼくはじぶんのあたまがおかしくなったのかと思いました。そして、やっぱりじぶんがまちがっているのかと思いました。あした友だちのリカちゃんにあうので、じぶんがまちがっていないか、こいちじかんといつめるつもりです。
2006-03-17 22:14:47 / ふじさわ / Comment: 0 / Trackback: 0

# AA折れ線グラフ

OSS WEB|column|今日の一行|2006年3月

遅ればせながら、ぼくも解いてみました。ぜぇぜぇ。

(define (plot istring)
  (receive (nlist nlmax nlmin)
      (let loop ((cl (string->list istring)) (curr 0)
                 (cmax 0) (cmin 0)
                 (out '()))
        (if (null? cl)
            (values (reverse out) cmax cmin)
            (case (car cl)
              ((#\R) (loop (cdr cl) (+ curr 1)
                           (max cmax curr) (min cmin curr)
                           (cons (cons curr #\/) out)))
              ((#\F) (loop (cdr cl) (- curr 1)
                           (max cmax curr) (min cmin curr)
                           (cons (cons (- curr 1) #\\) out)))
              (else (loop (cdr cl) curr cmax cmin
                          (cons (cons curr #\_) out))))))
    (let yloop ((yaxis nlmax))
      (when (>= yaxis nlmin)
        (let xloop ((xaxis 0) (nlist nlist))
          (if (null? nlist)
              (begin (display "\n") (yloop (- yaxis 1)))
              (begin (display (if (= (car (car nlist)) yaxis)
                                  (cdr (car nlist))
                                  #\ ))
                     (xloop (+ xaxis 1) (cdr nlist)))))))))

力技が好きです。でも象さんのほうがもーっと好きです☆

TODO: リファレンスマニュアルのgauche.sequenceを読んでみること。
2006-03-17 22:00:36 / ふじさわ / Comment: 0 / Trackback: 0

# 商品がなくても200を返そう。そのかわりに……

ステータス200なのに「その商品はありません」

「商品がないときは404を返そう」という指摘。それは違うんじゃないの?とコメントを書きこんだつもりが(すぐには?)反映されなくて、手元にテキストも残ってなくて不安なのでここにメモ。

「商品がない」のと「ページがない」のは違う。たとえばWikiで、存在しないページにアクセスすると、200と編集画面が返ってくる。ここで404と編集画面を返すとおかしくなる。404と「Not Found」もだめ(まぁ議論の余地がありそうだけど)。HTTPのレイヤーでページがないのと、Wikiのレイヤーでページがないのは違うからだ。

これと同様に、Webアプリケーションのレイヤーで「商品がない」のとHTTPレイヤーで「ページがない」のは違う。たしかにこれは、システムの仕組みが分からない人には混乱のもとだ。だけど、エンジニアリング的には正しいはず。また、検索エンジンにしてみても、「商品がない」のと「ページがない」のは違うものと認識した設計をするのが本筋のはずだ。

Web設計者が本来やるべきことは、存在しない商品にできるだけリンクが貼られないようにするURL設計や、もし在庫切れ商品にアクセスされた場合には「その商品は売り切れです。次の入荷は……」、「在庫切れ、または絶版商品です。同様の商品をお探しの場合は……」といった表示を返すことじゃなかろうか。
2006-03-17 10:30:04 / ふじさわ / Comment: 11 / Trackback: 0

2006-03-16

# 3月18日のオープンソースカンファレンス2006に参加します

イベントの宣伝をば。Wiki好きが集まって雑談したり飲み会したりする「Wikiばな」では、この週末、3月18日に開催されるオープンソースカンファレンス2006(長いので、以下「OSC2006」と省略)に出展します。
Wikiばなプレゼンツ/OSC2006 

内容は、「Wiki記法のエトセトラ」。「Wikiってなんか敷居が高い」、「よく分からない」、「掲示板のほうがいい」、「記法とか必要ない」、世間にはそういう声があるようで、もっともだなぁと思います。Wiki屋さんもそういう問題があるのを一応認識していて、最近ではワープロのようにGUIで文面を編集できるWikiエンジンを作ったりもしているようです。

OSC2006では、より使いやすいWikiを目指して、現存するWiki記法や、GUIで文面を編集できるWikiエンジンについて説明します。話者はWalWikiの開発者である塚本 牧生さん。参加費無料ですし、気軽にお話できる時間もあると思います。ぼくも資料の展示要員として参加しますので、ご興味のある方はぜひいらしてください。
2006-03-16 10:37:27 / ふじさわ / Comment: 0 / Trackback: 0

2006-03-15

# 株は怖いねぇという話

 500万円そこそこの蓄えのほとんどを1社の株式につぎ込ませる。しかも顧客は79歳と高齢で金融知識もなく、職業にもついていない。営業マンからいわれるままに売り買いするスタイル。これが本当なら、これはあきらかに適合性の原則違反だ。
 
 適合性の原則とは、「投資勧誘に際して、顧客の知識、経験及び財産の状況に照らして適当と認められる取引の勧誘を行わなければならないというルール」をいう。証券会社は必ず、勧誘方針の中にこれを守るという条項を入れているはず。それはこれまでの数々の被害事例をふまえて導入されたものだ。それなのに、まだこんなことをやっているのか。当然ながら、これは営業マンの使用者である証券会社の責任でもある。"

なるほど。「適合性の原則」というのがあるのか。メモメモ。でもこれ、法律じゃなくてあくまで社内のルールなんだよね。証券会社の罪を問うのは難しそうだなぁ。(証券会社のモラルなら、小一時間問い詰められそうだけどw。でも、そんなことしても面白くないのでマスコミはそういうことしないよね)。

個人的に、このおばあさんの話

 東京都内の無職女性(79)は昨年暮れ、証券会社の勧めでLD株を買い、1週間で100万円の利益が出た。さらなる値上がりを期待し、7000株を買い増した。  東京地検の家宅捜索後、眠れない日が続いた。2月に売って500万円の差損が出ると、蓄えがほとんどなくなった。同居している息子家族のために自宅をリフォームするつもりだったが、できなくなった。 パソコンは持たない。情報源はテレビと新聞だけ。証券会社から電話で言われるままに売り買いしていた。「何とか挽回(ばんかい)しましょう」。むなしい言葉を最後に営業マンの電話は途絶えた。

を読んで考えてしまうのは、「1週間で100万円利益が出て、そこからさらに7000株突っ込もうと思う」のは、どういう人なんだろうなぁということだ。1週間で100万円? 元手500万円で? そんなもん、おかしいやないか。そんなうまい話があるわけない。

そこからさらに乗ろうって時点で、ただのギャンブラーか、楽して儲けることに罪悪感や危険を感じない、危うい人だと思うよ。こういうのは本当は、お父さんやお母さんが教えなければいけないことだと思うんだよ。ひとことで言えばリテラシーなんだろうけど、それだけじゃなくてね。

自然界に暮らすものが理解しておくべき感覚ですよ。「入力と出力が不釣り合いすぎる! なんかおかしい。なんか怖い。なにもしていない自分が、こんなに受け取っていいんやろうか?」って。そういう意味で、この人に同情すべきかどうか悩む。

また、こういうギャンブラーの構図を無視して「可哀想な人」扱いする朝日新聞の人も、ちょっと変だよねぇ。(もしかしたら「ザマアミロ」扱いなのかもしれないけど。結局は興味本位、釣り目的ということか……クマー)。
2006-03-15 18:53:22 / ふじさわ / Comment: 0 / Trackback: 0

# UMLじゃないものを使うという選択肢

ちょっといまさら感がありますけど、デブサミ2006に参加したとき感じたことを、1つアウトプットしてみます。
岩切さんの日記で、セッション資料ダウンロードベスト3というのが発表されてるんですけど、この中の「天使のSEと呼ばれる知恵〜現場ユーザーにも分かる業務フローはこれだ!」サントリー株式会社 片山隆というセッションに参加して、案外面白いと感じました。

片山さんというのはもともとシステム屋さん上がりの人で、サントリーへ転職して入った人なんですね。それでまぁバリバリ仕事をされているうちに実力を認められて、あるとき子会社立ち上げに際してその業務フローを定義するよう指示されたとのこと。そこで、普通ならUMLを使うのだけど、そうしないで独自フォーマットでワークフローを作ったというお話をされていました。

普通は「えー? 独自? まじですか?」と思うのだけど、なかなかこの人のお話に説得力があってね。「業務フローは、会社役員や現場の人が理解できたほうがいいと思った」とおっしゃっていました。上記URLにPDFがあって、その20ページ目に書かれてますけど、そういう業務フロー図を作るほうが、
- 開発者は業務理解に役立てられる
- ユーザーは自分の業務が全体の中でどういう役割なのかを理解できる(業務改善に使える)
- ユーザーは異動があったときスムーズに引き継ぎできる
- 開発者は、開発から保守フェーズへの引き継ぎをスムーズに行える
ということでした。

図の作成も、独自のソフトウェアを使うんじゃなくてパワーポイントを使って書く、とかね。こういうのって、結構大事じゃないかなぁと思うんですよね。「システムはナマモノ」と考えて、いろんな人が、いろんなきっかけで改善できるようにしておくというのは。一部の人がシステムを作って、そこに人員を歯車のように割り当てる。それじゃあ硬直しますよね。

要件が変わりにくいシステムを作る場合や、詳細仕様レベルならUMLもいいでしょうけど、場合によっては、積極的にUML以外を使う手もあるだろうなぁと。言うなれば(社内)バザール型の業務フロー定義かもしれない。あらためて振り返ってみると、要件定義のときにUMLは使えないですよね。現場の人間に確認してもらえないんだから。コーディングするときでも、全体を俯瞰するのは役に立ちますし、片山さんの提案されている方法って、結構いいんじゃないでしょうか。
2006-03-15 15:51:11 / ふじさわ / Comment: 0 / Trackback: 0

# 外で音楽を聞くこと

会社に行こうと電車に乗っていたら、目の前の席が2つ空いた。
ぼくはあと2駅で降りるので、まぁ座る気が起きないので立っていた。
そうしたら、後ろで雑談していたご婦人がたの一人が声をかけてきた。「こちら、よろしいですか?」
とっさのできごと。そのとき、僕はイヤホンをして音楽を聞きながら、しかもザウルスに集中していたのだ。

「いいですよ、どうぞ」。そう言いたいけれども声が出ない。コミュニケーションプロトコルのロードと、状況認識に少しばかり時間がかかる。イヤホンをしているので、不用意に声を出すと大きい音になりすぎるだろう。
結果としてまぁ、声を出すことはできず、なんとなく頭を下げるだけで、目を合わせることもなく意思表示をすることになった。失礼なことをしてしまったなぁ。

それで思ったのだけど、外で音楽を聞くことは、やっぱりよくない。音声が聞こえる状態というのは、コミュニケーションプロトコルを確立するために必要な最低限の条件だと思う。言葉だけでなく、いろんな媒体で人間はコミュニケーションできるけれども、音声と言葉によるものはもっとも、肌触りがよい。それを閉じるというのは、「コミュニケーションしませんよ」と言っているようなものだ。

とくに銀座線という場所では、それはよくないことだったなぁ。もうこの声は、あのお二人に届かないけど、ごめんなさい。でした。
2006-03-15 13:40:05 / ふじさわ / Comment: 0 / Trackback: 0
recent days<< | >>old days