Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2007-12-11

Practical Common Lisp (4)

| 21:54 | Practical Common Lisp (4) - わだばLisperになる を含むブックマーク はてなブックマーク - Practical Common Lisp (4) - わだばLisperになる

引き続きPractical Common Lisp 第三章3. Practical: A Simple Databaseを読んでみています。

Improving the User Interaction

とりあえず出てきたコードを写経して感想をメモ
(defun prompt-read (prompt)
  (format *query-io* "~A:" prompt)
  (force-output *query-io*)
  (read-line *query-io*))

できた。

*query-io*は初めて使った。

promptに好きな文字列を指定できるらしい。

多分、これでユーザからの問い合わせるのだろう。

(defun prompt-for-cd ()
  (make-cd
   (prompt-read "Title")
   (prompt-read "Artist")
   (prompt-read "Rating")
   (prompt-read "Ripped [Y/N]")))

できた、make-cdの対話的なバージョンの様子。

でもこれだと、rippedがy/nの入力ってことになるが。後で内部的にt/nilに変更するのだろうか。

(defun prompt-for-cd ()
  (make-cd
   (prompt-read "Title")
   (prompt-read "Artist")
   (or (parse-integer (prompt-read "Rating") :junk-allowed 'T) 0)
   (y-or-n-p "Ripped:")))

できた。y-or-n-pを使うことにしたらしい。これだと、y/nを、t/nilに変換できる。

それと、レイティングの数字は、そのままだと、文字列で取得することになるので、parse-integerでパーズしているのだろう。

それで、:junk-allowedをtにすることにより、不正な入力の場合でもエラーにしないで、nilを返すようにして、orでくるんで、デフォルト値を設定している様子。

しかし、y-or-n-pは、処理系によって微妙に動作が違うみたい。Clozure CL(OpenMCL)だと、前後に改行が入ったりする(printの動作に似た感じ)SBCLならそういうことはない。

(defun add-cds ()
  (loop (add-record (prompt-for-cd))
        (if (not (y-or-n-p "Another?")) (return))))

add-recordを対話的にするためのラッパーの様子。

本文を読む
  • *QUERY-IO*を使った問い合わせ方法の説明。
    • FORCE-OUTPUTの実行が必要な処理系もある。
  • READ-LINE関数の説明。
    • 取得する文字列に改行文字は含まれない。
  • PARSE-INTEGEの説明。
    • 不正な値の入力はデフォルトだとエラーになるが、:JUNK-ALLOWEDでTを指定すると、その場合でもNILを返すという挙動になる。
  • ORによるデフォルト値の設定
    • Perl等の、||や、&&演算子と同じ感覚で、and、orが使える。
  • Y-OR-N-Pの説明。
    • ユーザのy/nの入力をt/nilで返す。
  • LOOPの説明。
    • 簡単な無限ループとしての使い方の説明。脱出には、RETURNを使う。

次回、Saving and Loading the Databaseより再開。

CLOSチュートリアル (6)

| 15:18 | CLOSチュートリアル (6) - わだばLisperになる を含むブックマーク はてなブックマーク - CLOSチュートリアル (6) - わだばLisperになる

Common Lisp クックブックさんのところのCLOSのチュートリアルに新しい練習問題(CLOSチュートリアル - 4.4. すべてはオブジェクトの中にあるCLOSチュートリアル - 4.5. その他の特定子(まだCLOSオブジェクトは不要です))が出たので挑戦!。

4.4 問題.1

Lispの describe 関数は、処理中に describe-object 総称関数を呼び出します。各処理系は各クラスにこのメソッドを実装する必要があり(ただし、standard-object 以外のクラスへの実装は任意です。また、ユーザは自由にメソッドを追加して構いません)、このメソッドがオブジェクトとストリームの二つの引数を受け取るように実装しています。実装者が describe-object のすべてのメソッドを一つのファイルに書くべきか、複数のファイルに分散して書くべきか議論しなさい(例えば、aardvark で特定化されるメソッドを、クラス定義と他のメソッドと一緒に "aardvark.lisp" ファイルに書くべきかどうか)。で、どんな意見が出ましたか?

4.4 解答.1

他のオジェクト指向言語を触ったことがないので、普通がどういうものなのか良く分からないのですが、分けて書けてしまうということは、分けて書いた方が分かりやすいような使い方もできてしまうということかもしれず、別に全部一つに纏める必要はないんじゃないかと思う。

4.4 問題.2

二番目以降の複数の引数でメソッドを特定化しなければならない例をいくつか考えなさい。

4.4 解答.2

(defmethod concat ((str string) (num number))
  (concatenate 'string str (princ-to-string num)))

(defmethod concat ((num number) (str string))
  (concatenate 'string (princ-to-string num) str))

(defmethod concat ((n1 number) (n2 number))
  (concatenate 'string (princ-to-string n1) (princ-to-string n2)))

(defmethod concat ((s1 string) (s2 string))
  (concatenate 'string s1 s2))

とかどうだろう。ちょっと無理矢理な気もするけれど…。本当は可変長の引数が取れるようにしてみたかったけど、defmethodと&restの組み合わせの定番処理方法がいまいち良く分からず…。

4.5 問題.1

リストのための my-describe メソッドを書きなさい。

4.5 解答.1

(defmethod my-describe ((list list))
  (format t "~S is a list object~:[~;and a null object~]." list (null list)))

listは、nil+consなので、nilの場合に追加メッセージを表示するようにしてみた。

4.5 問題.2

antelope クラスのインスタンス Eric のための print-object メソッドを書きなさい。Eric のクラスを変更しても、そのメソッドはまだ適用可能だと思いますか?

4.5 解答.2

(defmethod print-object ((antelope antelope) stream)
  (print-unreadable-object (antelope stream :type 'T :identity 'T)
    (princ "[Hello, Antelope!]")))

Ericのクラスを変更してメソッドの挙動を確認

(class-of Eric)
;=> #<STANDARD-CLASS ANTELOPE>

(print-object eric t)
;=> #<ANTELOPE [Hello, Antelope!] #x300041D3065D>

(change-class eric 'aardvark)
;#<STANDARD-CLASS AARDVARK>

(print-object eric t)
;=> #<AARDVARK #x300041D3065D>

ということで、クラス変更によりantelopeの特定化からは外れた様子。