Lisp界隈(の一部?)で、Lispのプログラムをバトンがわりにして他の人に渡していくという、なにやら楽しそうなことをやってるなー、と思ってたら私の元までやってきた。雲の上から降りて来た感じで嬉しかったので、声をかけてくださった @nitro_idiotさん、どうもありがとうございました。
で、バトンを受け取ったはいいけれどプレッシャーを勝手に感じていたので割と戦々恐々しながらコードを書いた。晒し場所は http://gist.github.com/286019 。
もとのプログラムは英単語暗記補助ツール(ゲーム)で、私に回ってきた時点で、辞書への単語追加、辞書の検索と表示、英単語の意味をgoogle翻訳で拾う、 2種類の暗記ゲームのモードが実装されていた。
私が追加したコードは、Gray Streamを利用して暗記ゲームの回答時にログをファイル出力するというもので、SBCL以外よくわからなかったのでテキトーにラッパーライブラリらしき trivial-gray-streamsを利用してみた。
CL-USER> (hige:Pon)ようはこんな感じでゲームに回答したとき、いつの間にかログが出力されてました。不思議。ということがしたい。わざわざGrey Stream使う必要なんて無いというツッコミは禁止です。
;; setup dict...done
lisp (score: 0):
神の言語 [Ynq]: Y
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))なにが問題なのかと言うと、read-lineにログへ出力したい情報を渡せないということ。このままだと入力した回答しかログに残せず、正解なのか間違いなのかも分からない。これではログの価値はたぶん消え去る。
(let ((line (read-line (input-of stream))))
(format (log-output-of stream) "~A" line)
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さんという方だそうです.
直接引き継げなかったのが残念というか申し訳ないというかですが,今後の成り行きをこっそり見守ろうと思います.