2008年1月24日木曜日

Chapter 32 Conclusion: What's Next?

前説
Finding Lisp Libraries
Interfacing with Other Laguages
Make It Work, Make It Right, Make It Fast
Delivering Applications
Where to Go Next

特になし。

読了。

Chapter 31 Practical: An HTML Generation Library, the Compiler

前説

FOO言語においては、InterpreterとくらべてCompilerが最適化しているのは、テキストをできるだけまとめて出力するようにすること。


The Compiler


  • The compilerのアーキテクチャ。
  • html-compilerクラス。このオブジェクトにbackendの総称関数へ成されたopsを集積させる。
  • backendの総称関数は、前項へのops書き込み機能を持つ。
  • opsを最適化する関数にわたし、最適化される。
  • 最適化されたops vectorをgenerate-code関数が受け取り、CLのコードを吐く。


  • compilerがhtml-compilerのときのprocessor interface(メソッド)は、html-compilerへのopsの集積処理とする。
  • 関数sexp->opsを定義する。これは、前項を順次S式に適用してopsのvectorを作成する。
  • 関数optimize-static-outputを導入する。これは前項のvectorについて、raw-stringを合成する。
  • 関数generate-codeを導入する。これはopsに対して逐次総称関数op->codeを適用するだけ。
  • 総称関数op->codeを定義する。これが、それぞれのopを対応するLisp codeに変換する。
  • op->codeの定義でポイントは2つ。embed-valueとembed-code。
  • embed-valueは、Lispの変数の埋め込みに対応する。これは(princ-to-string value)が本質である。
  • embed-codeは、Lispのコードの埋め込みに対応する。これは、入力のコードをそのまま使える。



FOO Special Operators


  • Special Operatorは、CL本体と同じように、言語の通常の評価ルールでは実現できないことを実現するためのものである。
  • まず、現在のembed-codeの実装(そのまま)では、(p: (random 10))などで、(random 10)の値はすてられ、出力は

    となる。値が欲しいときもある。
  • そのために、:print、:formatを導入する。
  • :printは、embe-codeで検知され、そのbodyをembed-valueに渡す実装とする。
  • :formatは、それの引数がself-evaluatingであれば、それをemit-htmlに渡せる(Interpreterで使える)。Compilerのときは、引数はどんなLisp expressionsでもよい。


  • Special Operatorの実装方法。
  • まず、関数processの第一分岐としてprocess-special-formを呼ぶようにする。
  • Special formは、'html-special-operator(plist)に格納する。名前とlambdaの組で格納。
  • 個々のSpecial formの定義はマクロdefine-html-special-operatorで簡略化する。
  • 関数process-special-formは、plistからlambdaを取得して、formに適用するだけ。
  • これによって、Special Operatorの拡張をモジュール化できている。



FOO Macros


  • Special Operatorの実装方法と類似。
  • 'html-macro plistにマクロ名と処理lambdaを登録する。
  • ただし、ユーザはそのlambdaを直接書くのではなく、そのlambdaを作るための関数generate-macro-with-attributesなど(define-html-macroから呼ばれる構造とする。
  • generate-macro...は、ユーザから受け取ったマクロ定義(args and body)を、DISTRUCTURING-BINDに渡して、argsの置換をおこなうようにする。
  • 関数processの第二分岐にexpand-macor-form関数を登録する。これがマクロ展開を実行する。



The Public API


  • あり? なぜここで急にXHTML? *xhtml*がnil or t。
  • マクロin-html-styleを定義。
  • マクロhtmlを導入。
  • マクロhtmlはそれ自身ネスト可能であるし、その中身は*pretty*の値によって振舞が違うので、コード分岐を含んでもいる。すなわち単純な実装だとネストによって指数関数的にコードが増大してしまう。
  • それはmacroletで回避可能。


The End of the Line

JavaScriptのS式表現をつくる元気はありません。。。

Chapter 30 Practical: An HTML Generation Library, the Interpreter

気をとりなおして。
30章と31章については、各節のエッセンスをメモしていく形にします。


前説


  • Interpreter : FOOプログラムを受け取って、HTMLを生成する。
  • Compiler : FOOプログラム(CL埋め込みあり)を受け取って、CLのコードを生成する。



Designing a Domain-Specific Language

DSL設計は2段階。

  • DSLの構文というか書きぶりを決める。
  • それの処理系を実装する。


DSLの設計のポイントは、DSLによっていかに表現が「圧縮」されるかということ。


The FOO Language


  • Lisp objectsを基礎におく。
  • self-evaluating lisp objectsは、PRINC-TO-STRINGで変換したものをFOOでは出力する。このとき<>などのエスケープも行う。
  • HTMLの要素名をキーワードシンボルとする。キーワードシンボルを第一要素とするリストを、HTMLの要素に対応させる。
  • 属性は次の2つの表現が可能とする。
    表現1 (:p :id "x" "Foo")
    表現2 ((:p :id "x") "Foo")


Character Escaping


  • 要素と属性でエスケープ対象文字が異なる。
  • 対象文字を、*element-escape*, *attribute-escape*に格納する。
  • *escape*に場所場所でどちらかを割り当てるなどの運用をする。



Indenting Printer


  • indenting-printerというクラスに情報を格納してindentを制御する。
  • ただし、indenting-printerのindentation slotに入っている値に対応してindentするというだけの機構。
  • 文字列をindentして出力するための基本関数を定義。

    (defun emit (ip string) ...)
    (defun emit/no-newlines (ip string &key (start 0) end) ...)
    (defun indent-if-necessary (ip) ...)
    (defun emit-newline (ip) ...)
    (defun emit-freshline (ip) ...)




HTML Processor Interface


  • HTML Processorのインターフェイスは総称関数で定義する。
  • これはInterpreterとCompilerの両方に対応するため。
  • 総称関数は次の8つ。

    (defgeneric raw-string (processor string &optional newlines-p))
    (defgeneric newline (processor))
    (defgeneric freshline (processor))
    (defgeneric indent (processor))
    (defgeneric unindent (processor))
    (defgeneric toggle-indenting (processor))
    (defgeneric embed-value (processor value))
    (defgeneric embed-code (processor code))




The Pretty Printer Backend


  • html-pretty-printerというクラスを導入する。これは、slotにindenting-printerとtab-widthをもつ。
  • 前章の総称関数に対するメソッドの定義をする。そのとき、Indenting-printer節で定義した基本関数が使える。
  • embed-valueとembed-codeとは、Compilerのみで使用する。Interpreterではerrorとなるようにする。



The Basic Evaluation Rule


  • 評価としては、まずself-evaluatingならば、raw-string関数にわたす。
  • そうでなければ、それはFOO言語のcons-sexp形式となる。
  • process-cons-sexp-html関数を導入する。
  • この関数は、HTMLタグ出力、その中身の出力、インデントの管理、改行の管理を担当する。
  • これの振舞の観点から、HTML要素は3つに分類できる。

    (defparameter *block-elements* '(:body :colgroup ...))
    (defparameter *paragraph-elements* '(:area :base :blockquote ...))
    (defparameter *inline-elements* '(:a :abbr ...))

  • この他に2つの補足的分類がある。

    (defparameter *empty-elements* '(:area :base :br ...))
    (defparameter *preserve-whitespace-elements* '(:pre :script ...))

  • この分類を利用して、process-cons-sexp-htmlを実装する。
  • process関数を直に呼ぶのでは手間なので、emit-html関数を導入して省く。
  • *html-ouput*自身をAPIとして公開したくはないので、with-html-ouputマクロを導入して隠蔽する。



What's Next?

特になし。

2008年1月23日水曜日

Chapter 29 Practical: An MP3 Browser

前説

特になし。


Playlists

SHOUTcastの情報がなかなかみつからない。IcecastはSHOUTcastから派生したものらしい。

あとPlaylistの情報。



Playlists As Song Sources

著者がちゃんと説明しないので、私家版整理。

  • MP3をストリーム配信する場合、提供の仕方は2種類ある。ラジオ的なエンドレスなものと、アーカイブス的に指定した曲を提供するものである。
  • いずれにしても、SHOUTcastの仕組みとPlaylistは関係ない。MP3プレーヤに直にラジオ(チャンネル)や曲のURLを直に入力してもよい。
  • PlaylistはSHOUTcastを使ったサービスを便利にするための補完的なものである。
  • MP3 client(の一部)は(Nullsoftの)Playlistを読み込むことができる。
  • ラジオの場合は、Playlistの中のLengthが-1となっている。
  • 曲の場合は、その曲の秒数がLengthに入る。
  • ラジオの場合は、通常Playlistは単にそのチャンネルの聴取する入口の機能のみを担い、Playlistをユーザが編集するなどの機能はない。
  • 曲の場合は、Playlistからユーザが曲を選択して聴取することができるので、サーバ側がPlaylistの編集機能などを提供することによって便利になることもある。ただし、一度ダウンロードしたPlaylistをclient側でカスタマイズするというのもありなので、それしかやりようがないわけではない。
  • この本では、次の設計方針としている。

    • ラジオではなくアーカイブスとするが、曲毎のURLはもたない。
    • ユーザをIPアドレスで識別する。
    • それと相俟って、IPアドレスひとつにつきPlaylistをひとつサーバ上にもてるようにする。このPlaylistはNullsoftのPlaylistではない。
    • サーバ上のPlaylistをユーザがWebブラウザからカスタマイズできるようにする。
    • MP3 clientは単一のURL(ストリーミングフィード)にアクセスし、そのフィードから出る曲をWebブラウザからPlaylistという形で操作する。



Manipulating the Playlist
Query Parameter Types
Boilerplate HTML
The Browse Page
The Playlist
Finding a Playlist
Running the App

特になし。

この章楽しめませんでした。
CLの本ですから、作るアプリのドメイン情報やアーキテクチャについて、詳細に触れる必要はありませんが、説明がいいかげんに思えます。また、題材となっているSHOUTcastやPlaylistはNullsoftの勝手仕様なものであり、その仕様を自助努力で調べようにも入手可能な情報自体が不足しています。著者のCLのコードをみて仕様を想像するのでは、それが正しい実装なのか判断できません。

2008年1月22日火曜日

Chapter 28 Practical: A Shoutcast Server

前説
The Shoutcast Protocol

特になし。


Song Sources

うーん。やっぱりこの著者は、ドメインの説明が下手かな。
参考情報。


Implementing Shoutcast

特になし。

この章も楽しめました。
CLならではかな、と思えるところを振り返ってみると、

  • いろんなtypeのソースに総称関数で備えるところ。
  • 関数名とデータ名とアクセサなどが括弧の中で入り乱れつつ、アルゴリズムや意味を形成しているところ。

    • これっていいのか悪いのか、というのはありました。例えば、

      (index source)
      は、sourceオブジェクトに対するindex slotのリーダーを使っているのですが、CLではこれがそういう行為だという意味をこの表現は運んでいません。意図的なのですが。でも、source.getIndex()だったら、そういう行為だということは一目瞭然ではあるんですよね。


でしょうか。

Chapter 27 Practical: An MP3 Database

前説

特になし。


The Database

おいおい、テーブルから始めるんですか。。。

  • クラスtable は rowsとschemaというslotsを持つ。rowsは関数make-rowsによって初期化される。
  • rowsは a vectorに格納されるようにする。
  • make-rowsはmake-arrayの単純なラッパーになる。
  • クラスcolumnはschemaの構成要素である。
  • クラスcolumnは次のslotsからなる。

    • name
    • equality-predicate
    • comparator
    • default-value 初期値はnil
    • value-normalizer ここのinitformに何故このようなlambdaを置いているのか理解できない。(↓で解決)




Defining a Schema


  • equality-predicateとcomparatorの組は、型を定義することと同義である。
  • column objectsをmake-instanceで直に作るより、型を指定して生成するインターフェイスの方が便利。
  • ここでは総称関数を使う方法をとる。
    (defgeneric make-column (name type &optional default-value))
  • stringとnumberについてeql-specialized methodを定義する。
  • stringのvalue-normalizerは#'not-nullableという関数。nilだとsignalを上げる。
  • numberはvalue-normalizerは指定しない。すなわちinitformのもの。
  • interned-string向けにはまずcolumnのサブクラスを定義する。
    (defclass interned-values-column (column) ...)
  • これにはinterned-valuesというa slotを追加する。これはhash。
  • value-normalizerで、intern処理をする。関数名はintern-for-column。
  • interned-string用のmake-columnも定義。
  • これで、make-columnは、string,number,interned-stringについて定義できた。
  • make-schemaを次のように定義。

    (defun make-schema (spec)
    (mapcar #'(lambda (column-spec) (apply #'make-column column-spec)) spec))

  • specの例は次のとおり。

    (defparameter *mp3-schema*
    (make-schema
    '((:file string)
    (:genre interned-string "Unknown")
    (:artist interned-string "Unknown")
    (:album interned-string "Unknown")
    (:song string)
    (:track number 0)
    (:year number 0)
    (:id3-size number))))




Inserting Values

  • insert-rowはtableにa rowを挿入する関数である。
  • normalize-rowというヘルパー関数を作る。
  • names-and-valuesという引数を用意する。これはa plist。
  • normalize-for-columnというヘルパー関数を用意する。これはcolumn毎のvalue-normalizerを呼ぶ。


  • 関数file-rowは、MP3ファイルからID3情報をread-id3で抽出した上で、それをrowとして*mp3s*に格納するためのplistを作成する。



Querying the Database

うう、別にRDBを作りたくはないのだが。。。どこに連れていく気なんだ。。。


Matching Functions
Getting at the Results
Other Database Operations

特になし。


チュートリアルとしてはいろいろ参考になったのですが、作っているのがRDBなので、それは既存のRDBを使えばいいんじゃないの、とついつい思ってしまいます。バイナリデータのときとかは、あまりそう思わなかったのですが、なんででしょうね。

2008年1月21日月曜日

Chapter 26 Practical: Web Programming with AllegroServe

前説
A 30-Second Intro to Server-Side Web Programming

特になし。


AllegroServe

(defpackage :com.gigamonkyes.web
(:use :cl :net.aserve :com.gigamonkeys.html))

する前に、com.gigamonkeys.htmlのasdfによる読み込みが必要。


Generating Dynamic Content with AllegroServe

特になし。


Generating HTML

"The macro version will be quite a bit more efficient than the emit-html version. Not only do you never have to generate an s-expression representing the whole page, also much of the work that emit-html does at runtime to interpret the s-expression will be done once, when the macro is expanded, rather than every time the code is run."
が大事なことをいっていると思うのだが、理解できない。とりあえずノートしておく。

;; 追記
ああ、なぜ理解できないかはわかった。ここでいっていることの真偽は、結局htmlマクロってどうかかれているの? ということによるからだ。で、それは示されていないと。ここではそういう風にhtmlマクロは作られている、とだけ理解しておけばいいと解釈。


HTML Macro

特になし。


Query Parameters

simple-formが、なぜか出力がREPLに表示されて、WEBブラウザに出ない。
ここ、まず::typeは誤植かな。
あと、let ((*html-output* ...としているところは、(with-html-output ...でしょうか。とりあえず、そうしたら動きました。random-numberも同じです。errataをみると、、、出てない。著者に送っとこうかな。


Cookeis

特になし。


A Small Application Framewok

特になし。


CLを使ったWebアプリ開発の可能性を感じることができました。