孤独にそっくり

開いている窓の前で立ち止まるな

実践Common Lispを読む 第30章〜第32章 読了

Practical Common Lisp
こんにちは。今回で「実践Common Lispを読む」は最後になります。

第30章 実践:HTML生成ライブラリ インタプリタ

FOOは、関数やクラスやマクロから構成されるAPIではなく、CommonLispプログラムに組み込み可能な特定用途向け言語を処理する言語プロセッサを提供する

いわば言語指向のプログラミングらしい?
lolにあったドメイン特化言語(DSL) とは同じっぽい
FOOでは2つの言語プロセッサを提供している。1つはHTMLを生成するためにFOOの「プログラム」をデータとして受け取り、解釈するインタプリタ
もうひとつは場合によってはCommonLispのコードが組み込まれているFOOの式を受け取り、そこからHTMLを生成してコードを実行するコンパイラ
前者はemit-htmlで、後者はhtmlマクロ。

*特定用途向け言語の設計

組み込み言語の設計には

  • 表現したいと考えている内容を記述できる
  • 「プログラム」を受け取って、指示された動作を実行するか、同等の動作をするCommonLispのコードに変換する

というプロセスが必要
その時には表現力と簡潔さのバランスが求められる

*FOO言語

もっとも単純なFOOフォームは自己評価型のLispオブジェクト(文字列、数字、キーワードシンボル)
属性ってのがなんのためにあるのかわからんけどリストのシンボルの直後におくか、リストのRESTによって表現するかの2通りがある。
このシンタックスの違いを抽象化したいなら、HMTLタグ、属性リスト、本体の3つにパースする関数parse-cons-formを定義すればいい
ひとまずインタプリタでもコンパイルでも、いい感じにインデントされた出力が欲しいだろうから、それを先につくる

*文字のエスケープ

「<>&'"」あたりを「<」や「>」とかに置き換えていきたい。
そのためにescape-charとescape関数で実現する

*インデントプリンタ

出力ストリームをラップしたindenting-printerクラスを定義する
改行とか文字列の出力とかを実現するためのemit関数等を定義

*HTMLプロセッサインターフェース

2つの実装のための総称関数を定義

*プリティプリンタのバックエンド

スロットとタブ幅を保持するクラスやメソッドの実装をする
prettyの値によって処理を分岐
インタプリタLispの式を評価する方法として、EVALもある

*基本的な評価のルール

あるオブジェクトを受けてHTMLを生成するための適切な処理や実行する関数が必要
FOOフォームか否かを判定してprocess-sexp-html関数に引き渡す関数を定義。
...割愛

第31章 実践:HTML生成ライブラリ コンパイラ

コンパイラインタプリタの主な違いは、インタプリタがプログラムを処理して直接動作するのに対し、コンパイラは同じプログラムを処理することで同じ振る舞いを示す別の言語のコードを生成する点。

逐一コードを読む気にもならず、さらっと流し読みしてしまった・・・
ちゃんとHTMLを生成出来るようになったし、特殊オペレータも使えるようになった。(
EVAL-WHENオペレータは本体のコードによって引き起こされる効果がCOMPLILE-FIELを使ってコンパイルされている間にのみ可視状態になることを保証するもの。)
マクロも書ける。
「終わりに」の所で組み込みJavaScriptの生成のサポートをすることについて触れられているのはすごいことじゃないですか?

第32章 結論:さて次は?

自分でLispについて学ぶためのtips

ライブラリ探し
とりあえず動くから正しく速くへ

「早計な最適化は諸悪の根源」
CommonLispは遅くない。
速くするには、timeマクロを使ってチューニングすべきボトルネックを探すか、アルゴリズムを変えるかを考えるべきだけど、コードバミング(余計なことは一切しないコード、コード狂い)に陥るかもしれない。DISASSEMBLE関数を使うとコードをアセンブリ言語風にダンプしてくれるから、無駄が分かるかも。

CL-USER> (defun add (x y) (+ x y))
ADD                             
CL-USER> (disassemble 'add)
; disassembly for ADD                                                          ; Size: 28 bytes                                                               
; 05B811FD:       488B55F8         MOV RDX, [RBP-8]           
; no-arg-parsing 
entry point                                                                    
;      201:       488B7DF0         MOV RDI, [RBP-16]                           
;      205:       41BBF0010020     MOV R11D, 536871408        ; GENERIC-+      
;      20B:       41FFD3           CALL R11                                    
;      20E:       488BE5           MOV RSP, RBP                                
;      211:       F8               CLC                                         
;      212:       5D               POP RBP                                     
;      213:       C3               RET                                         
;      214:       CC0A             BREAK 10                   ; error trap     
;      216:       02               BYTE #X02                                   
;      217:       19               BYTE #X19                  ; INVALID-ARG-COU
NT-ERROR                                                                       
;      218:       9A               BYTE #X9A                  ; RCX            
NIL  
アプリケーションの配布

ソースファイルをloadするか、システム定義ツールASDFを使うといい。
エンドユーザ向けには、WindowsのDLLのような形式がない。Lispにはプログラミングのきちんとした定義がないからだ。使っているものによって解決策は色々あるっぽい。

次のステージ

ぜひいますぐ自分のLispコードを書き始めて欲しい

Lisperと触れ合うなら

書籍
リファレンス

オブジェクトシステム

  • Sonya Keene:"Object-Oriented Programming in Common Lisp

オブジェクトウィザードになる、頭の体操

  • G.Kiczales,Jim des R.,D.G. Bobrow:"The Art of the Metaobject Protocol"

Common Lispについて

ビットレベルの動作

  • Christian Queinnec:"Lisp in Small Pieces"

理論的なの

その他もろもろ

元の本をぐぐってたら、OnlineProgrammingBooks.comっていうサイトに行き着いた。
Common Lispの本で名前を見たことがあるやつはだいたいある。英語だけど・・・
http://www.onlineprogrammingbooks.com/lisp/


「言語を本当に身につける唯一の方法は使ってみることだ。ここまで来たのなら、もちろんその準備はできている。それでは、Happy hacking!」

全体の感想

この本を読み始めてから、早いもので2か月以上が経ちました。2か月前に比べてコードがスラスラ読めて書けるようになったかといえば残念ながらそんなことはありません。わからないまま読み飛ばしたところもかなりそのままになっています。特に後半の実践の章に入ってからはコードを追うのも辛く、大抵コードをそのまま読むことはせずに解説の文章ばかりを目で追っていました。それでも、Emacs+SLIMEを抵抗なく使うようになってきたし、いくつか面白いコードに出会ったりしたのでまったく無駄だったわけではないと思います。前回読んでいたLand of Lispとはまた違った方向の本でした。パッケージを使って大規模なアプリケーションを構築していくのはそれこそ「実践」だったと思います。Common Lispはなんでもできるんや!と思い知らされました。
 今回で、Common Lispに関する本は2冊目です。本を読むとき以外は全くプログラミングをしていないので、そろそろ自分で何かを作ってみたいなと思い始めています。思うだけで終わらなければいいですが・・・。
 あと、この本を借りるときに一緒に借りてきた「関数プログラミング実践入門」という本を暇なときに眺めていたのですが、どうやらHaskellという言語の本らしいです。この本でも言及されているように、Common Lispは純粋な関数型言語ではないことは実践Common Lispでも最初のほうに書かれていたことです。それに対して、Haskellはとても純粋な関数型言語らしく、また謎の世界を垣間見てしまいそうだなと思っています。これはコードを動かしたりせずに適当に流し読みするつもりです。
 今後は、ひとまず自分でいろいろ書いてみたいなと思っています。Common Lispについての情報を何となくRedittやQiitaで読んでみたりしているので、そのソースを読んだりもしています。それでもうちょいステップアップしたいなーと思ったらOn Lispを読んだりすると思います。たぶん。でも10月に応用情報受けるんで勉強しないとなとか、ドン・キホーテの後編を読まないとなーとかジムでムキムキになりたいなーとか思っているので、プログラミングをする時間があるかは微妙です。

最後らへんは飛ばし気味だったので記事としてほぼ価値がありませんが、「実践Common Lispを読む」は今回で終了になります。ありがとうございました。lolと同じように、またいつか読み直したいです。