2010年1月28日木曜日

CLコードバトンに参加した(2010/01/26にFork)

Lisp界隈(の一部?)で、Lispのプログラムをバトンがわりにして他の人に渡していくという、なにやら楽しそうなことをやってるなー、と思ってたら私の元までやってきた。雲の上から降りて来た感じで嬉しかったので、声をかけてくださった @nitro_idiotさん、どうもありがとうございました。

で、バトンを受け取ったはいいけれどプレッシャーを勝手に感じていたので割と戦々恐々しながらコードを書いた。晒し場所は http://gist.github.com/286019

もとのプログラムは英単語暗記補助ツール(ゲーム)で、私に回ってきた時点で、辞書への単語追加、辞書の検索と表示、英単語の意味をgoogle翻訳で拾う、 2種類の暗記ゲームのモードが実装されていた。

私が追加したコードは、Gray Streamを利用して暗記ゲームの回答時にログをファイル出力するというもので、SBCL以外よくわからなかったのでテキトーにラッパーライブラリらしき trivial-gray-streamsを利用してみた。

CL-USER> (hige:Pon)
;; setup dict...done
lisp (score: 0):

神の言語 [Ynq]: Y
ようはこんな感じでゲームに回答したとき、いつの間にかログが出力されてました。不思議。ということがしたい。わざわざGrey Stream使う必要なんて無いというツッコミは禁止です。

Gray Stream用のクラスを作る

実装するのになにが必要かというと、"入力時にログを吐くストリーム"クラスを作って、メソッドを実装すること。

(defclass logged-input-stream (trivial-gray-streams:fundamental-character-stream)
((log-output :accessor log-output-of :initarg :log-output :initform nil)
(input :accessor input-of :initform *query-io*)))

回答する際は*query-io*からreadやread-lineしてるようなので、こいつのかわりに定義したクラスのオブジェクトからread-lineするようにしてやる。どうもGray Streamでreadを定義することが出来なさそうなので、readしている箇所は read-lineで得た文字列にread-from-stringを使うという手段で問題を回避した。

ダイナミックにいこう

さて、あとはread-lineを実装するだけ、と、いい気分になってメソッドを実装してる途中に根本的な問題に気づいた。

最初に書こうとしたread-lineの実装はこのようなもの。

(defmethod trivial-gray-streams:stream-read-line ((stream logged-input-stream))
(let ((line (read-line (input-of stream))))
(format (log-output-of stream) "~A" line)
line))
なにが問題なのかと言うと、read-lineにログへ出力したい情報を渡せないということ。このままだと入力した回答しかログに残せず、正解なのか間違いなのかも分からない。これではログの価値はたぶん消え去る。

どうしよう、どうしよう、どうしようと3分くらい悩んで出した結論は、

(defparameter *entry* nil)

ダイナミック変数を使う、でした。

これならread-lineを呼ぶ前にletで設定して呼び出し元から情報を渡せそうだ。

最終的なread-lineがこちら。

(defmethod trivial-gray-streams:stream-read-line ((stream logged-input-stream))
(let ((line (read-line (input-of stream)))
(log (log-output-of stream)))
(when log
(case (car *mode*)
;;*mode* = (:pen n meaning?)
((:pen)
(log-pen log *entry* line (second *mode*) *choices-list* (third *mode*)))
;;*mode* = (:pon)
((:pon)
(log-pon log *entry* line))
(T nil)))
line))

きっとツッコミどころはたくさんあるのだろうなぁ。人に見られるコードを書くというプレッシャーの中で、普段考えないことを考て勉強になったと思う。

こういったネタをやっているのを見つけたら、恐れずに参加するようにしたい。


バトンを回す次の人のあてが全くなくて困っていたところ,@g000001さんが助けてくださいました.

どうやらchatonで救世主が舞い降りたようで,次はkoshさんという方だそうです.

直接引き継げなかったのが残念というか申し訳ないというかですが,今後の成り行きをこっそり見守ろうと思います.


2010年1月25日月曜日

日本酒酒購入 まさるや(2010/01/25)

大学に行く途中で寄り道して、日本酒を買った。

まさるやという名前の、小田急線鶴川駅(町田から2駅)から徒歩30分くらいの団地の中にある酒屋だった。

  • 山和 特別純米(山和酒造店/宮城)

2010年1月13日水曜日

メモ:Multiboot Specification

前に調べたことをメモしておく。

Multiboot Specification準拠のブートローダ(つまりはGRUB)からカーネルを起動したときの状態について。

  • EAXレジスタ マジックナンバー0x2BADB002
  • EBXレジスタ Multibootの情報を持つ構造体へのポインタ
  • A20GATE 有効 (メモリアドレス1M以上へのアクセス有効)
  • CR0レジスタ ビット31(PG) クリア (ページング無効)
  • CR0レジスタ ビット0(PE) セット (32ビットモード)
  • EFLAGSレジスタ ビット17(VM) クリア (プロテクトモード)
  • EFLAGSレジスタ ビット9(IF) クリア (割り込み無効)
  • ESPレジスタ 未設定
  • GDTR ブートストラップローダが作成したセグメント
  • IDTR 未設定
  • カーネルが読み込まれるのは0x100000番地

アセンブラで書いたカーネルの先頭が0x100000となるようにリンカスクリプトを書く。たぶんこんなの。

ENTRY(_start)
SECTIONS
{
. = 0x100000;
.text :{
*(.start);
*(.text);
}
.data :{
*(.data);
}
.bss :{
*(.bss);
}
end = .;
}

2010年1月1日金曜日

2010年初めての飲酒

あけましておめでとうございます。

とうとう2010年がやってきたようなので、手をつけずにいたウィスキーを飲むことにしました。

10月辺りに買っておいたキルホーマン3年ファーストリリースINAUGURALです。空になっても、記念に瓶をとっておこうかと思います。