ANA国内線【PR】
カテゴリ:一人読書会
  • On Lisp 第17章 リードマクロ
    [ 2009-12-16 23:55 ]
  • On Lisp 第16章 マクロを定義するマクロ
    [ 2009-12-12 23:55 ]
  • On Lisp 第15章 関数を返すマクロ
    [ 2009-12-09 23:55 ]
  • On Lisp 第14章 アナフォリックマクロ
    [ 2009-12-02 23:55 ]
  • On Lisp 第13章 コンパイル時の計算処理
    [ 2009-12-01 23:55 ]
  • On Lisp 第12章 汎変数
    [ 2009-11-25 23:55 ]
  • On Lisp 第11章 古典的なマクロ
    [ 2009-11-20 19:27 ]
  • On Lisp 第10章 マクロのその他の落とし穴
    [ 2009-11-17 23:55 ]
  • On Lisp 第9章 変数捕捉
    [ 2009-11-15 23:55 ]
  • On Lisp 第8章 いつマクロを使うべきか
    [ 2009-11-12 23:55 ]
On Lisp 第17章 リードマクロ
 リードマクロは、普通のマクロよりも Lisp 言語そのものをいじってる感が強いですなぁ。

Lisp のS式の生涯で重要な3つの瞬間
- 読み込み時
ー コンパイル時
- 実行時

リードマクロ => 読み込み時に機能

17.1 マクロ文字
- マクロ文字: Lips のリーダに特別な扱いを要求する文字
(例、"開き括弧")
- set-macro-character, リードマクロの定義
- クォート (') は、Lisp 最古参のリードマクロの一つ
(set-macro-character #\'
#'(lambda (stream char)
(list 'quote (read stream t nil t))))

- read の引数の最後の3つ
1. ファイル終端に達したときにエラーを起こすか
2. 起こさないなら何の値を返すか
3. read を呼び出している間にも read が呼び出されるかどうか
* ほとんどすべてのリードマクロで、第2、第4引数は t であるべき
# 参考: read - refwiki

17.2 マクロ文字のディスパッチング
- シャープ (#): ディスパッチングマクロ文字
- リードマクロを1文字以上で定義するため
ー make-dispatch-macro-character で独自のディスパッチングマクロ文字を定義可能
- # がデフォルトで定義されている
ー set-dispatch-macro-character, ディスパッチングマクロ文字の新たな組み合わせの定義

17.3 デリミタ
- read-delimited-list, 指定した文字が現れるまで Lisp オブジェクトを読み込み
結果のリストを返す
# 参考: read-delimited-list - refwiki


On Lisp
Paul Graham

4274066371
オーム社 2007-03
売り上げランキング : 82240
おすすめ平均 star

Amazonで詳しく見る
by G-Tools

by fkmn | 2009-12-16 23:55 | 一人読書会
On Lisp 第16章 マクロを定義するマクロ
 「関数を返すマクロ」があるのであれば、「マクロを定義するマクロ」を考えるのは自然な発想ですな。

第16章  マクロを定義するマクロ
- 省略名を定義するマクロ
- アクセス用マクロを定義するマクロ
- アナフォリックマクロを定義するマクロ

16.1 省略
- よく使われるオペレータの名前は短くあるべき
- バッククォートのついた任意の式を見ただけで
展開結果を言えるようになるとは思うべきではない
- マクロでは論理的に不要なかっこは省くのが良い

16.2 属性
- オブジェクト o が属性 p を持ち、その値が v である
=> o の属性リストを利用 (* 便利だが効率の悪い表現)
(setf (get o p) v)


16.3 アナフォリックマクロ
- aif, awhen, awhile, acond, alambda, ablock, aand
- a+, alist
=> アナフォリックマクロの定義は重複したコードになる
=> アナフォリックマクロを自動定義するマクロを作成できる
=> defanaph


On Lisp
Paul Graham

4274066371
オーム社 2007-03
売り上げランキング : 82240
おすすめ平均 star

Amazonで詳しく見る
by G-Tools

by fkmn | 2009-12-12 23:55 | 一人読書会
On Lisp 第15章 関数を返すマクロ
そろそろ紹介されるマクロが大きく複雑になってきて、ついていくのが少し大変になってきた。

15.2 Cdr部での再帰
- シンボルマクロが役に立つ例
- シンボルマクロを使用した場合
(defmacro alrec (rec &optional base)
"cltl2 version"
(let ((gfn (gensym)))
`(lrec #'(lambda (it ,gfn)
(symbol-macrolet ((rec (funcall ,gfn)))
,rec))
,base)))
(alrec (and (oddp it) rec) t)

- シンボルマクロを使用しない場合
(defmacro alrec (rec &optional base)
"cltl1 version"
(let ((gfn (gensym)))
`(lrec #'(lambda (it ,gfn)
(labels ((rec () (funcall ,gfn)))
,rec))
,base)))
(alrec (and (oddp it) (rec)) t) ;; シンボルマクロを使う場合に比べて、
;; rec を呼び出すための括弧が余計


15.3 部分ツリーでの再帰
- 関数生成関数を書いて、それにマクロのきれいなインタフェースをかぶせる



On Lisp
Paul Graham

4274066371
オーム社 2007-03
売り上げランキング : 82240
おすすめ平均 star

Amazonで詳しく見る
by G-Tools

by fkmn | 2009-12-09 23:55 | 一人読書会
On Lisp 第14章 アナフォリックマクロ
 アナフォリックって何かと思ったら、要は Perl の $_ に相当するものだとのこと。考え方自体は割と単純。試しに、aif を Ruby でそれっぽく実装してみると、こんな感じか。
def aif(test, &then_form)
@it = test
if @it
then_form.call
end
end

aif 'a' do
puts @it #=> a
end

ただ、else は簡単には再現できそうにない。この辺りでマクロの強力さを思い知る。

  - アナフォラ => 「それ」、「it」、Perl の $_
- 意図的にシンボル it を補足する
- 意図的に変数補足を行うマクロのエクスポート
=> 補足されるシンボルのエクスポートも必要
* パッケージ foo 内の (捕捉される) it は、フルネームでは foo:it

14.1 アナフォリックな変種オペレータ
- アナフォリックな if, when, while, and, cond, lambda, block の例

14.2 失敗
- 真、偽、失敗の判別
=> 多値を利用する
* gethash は、第一返り値がデータ、第二返り値が成功 or 失敗の表現
3通りの場合を判別するイディオム (マクロによる隠蔽が有効)
(defun edible? (x)
(multiple-value-bind (val found?) (gethash x edible)
(if found?
(if val 'yes 'no)
'maybe)))


# 関数をクロージャとして使うテクニック (イディオム?)
# 図14.4 で gensym の複数回評価を避けるために使用
(let ((x 0))
(defun inc ()
(setq x (1+ x))))
(inc) ;=> 1
(inc) ;=> 2
(inc) ;=> 3


14.3 参照の透明性
- Gelernter と Jagannathan の (プログラミング言語に対する) 定義
1. どの部分式も、値の等しい別の式に置き換えることができる
2. 同一コンテキスト内では、同じ式はどこで何回使われても同じ値を返す



On Lisp
Paul Graham

4274066371
オーム社 2007-03
売り上げランキング : 82240
おすすめ平均 star

Amazonで詳しく見る
by G-Tools

by fkmn | 2009-12-02 23:55 | 一人読書会
On Lisp 第13章 コンパイル時の計算処理
 コンパイル時にできる事をできるだけやってしまうことで、高速化をはかることができる。
 ベジエ曲線の例はちょっとついていけなかった。ついていく必要も無い気がするけどw
 もう少し実用的な例は、後の章で出てくるらしい。
 
13.1 新しいユーティリティ
- 引数の一部がコンパイル時に分かっているときは、
マクロを使って効率の良いコードを生成できる。



On Lisp
Paul Graham

4274066371
オーム社 2007-03
売り上げランキング : 82240
おすすめ平均 star

Amazonで詳しく見る
by G-Tools

by fkmn | 2009-12-01 23:55 | 一人読書会
On Lisp 第12章 汎変数
 setf に絡むマクロの章。
 何となく基本テクニックっぽい感じがするのは気のせいか。

12.1 汎変数という概念
- インバージョン: 値を求める式からアサーションへの変換
- アサーション: 成り立つべき条件
- Common Lisp で頻繁に使われるアクセス関数 (car, cdr, nth, aref, etc...) には、
インバージョンに当たるものがあらかじめ定義されている
- 汎変数: setf の第一引数として機能する式

12.2 複数回の評価に関わる問題
- define-modify-macro
- arg1, 定義したいマクロの名前
- arg2, 汎変数以外に取る付加的な引数
- arg3, 汎変数の新しい値を返す関数 (名)

12.3 さらに複雑なユーティリティ
- get-setf-method, 汎変数の値をいじくるための情報を返す関数
# 注、ANSI Common Lisp の標準は、get-setf-expansion
# 参考: 代入を簡略化するマクロ
- (get-setf-method '(aref a (incf i))
;;=> (#:G3430 #:G3431) ; 一時変数のリスト
;; (A (INCF I)) ; 一時変数にそれぞれ代入すべき値のリスト
;; (#:G3432) ; 変更後の値を入れるための一時変数
;; (SYSTEM::STORE #:G3430 #:G3431 #:G3432) ; この束縛のもとで行うべき代入操作
;; (AREF #:G3430 #:G3431) ; 変更前の汎変数の値を返す式

12.5 インバージョンを定義する
- defsetf, インバージョン定義マクロ
defmacro と違い、引数のために自動的に gensym を生成する
- defun でも、setf に対するインバージョンを直接定義できる (CLTL2 準拠の場合)
- 非対称なインバージョンも定義可能
- アクセス用の式とそのインバージョンは、同じデータに対して働く必要は無い



On Lisp
Paul Graham

4274066371
オーム社 2007-03
売り上げランキング : 82240
おすすめ平均 star

Amazonで詳しく見る
by G-Tools

by fkmn | 2009-11-25 23:55 | 一人読書会
On Lisp 第11章 古典的なマクロ
 だんだんマクロの規模が大きくなってきた。がんばってついていこう。

 ちなみに、最近、仕事でコードを書いていて、「あ、これマクロでやれそう (やりたい)」と考える事が多くなってきた。徐々に洗脳が進んでいるらしい。

よく使われる種類のマクロ
- コンテキストを作るマクロ
- 条件付き評価のためのマクロ
- 反復評価のためのマクロ

11.1 コンテキストの生成
- コンテキストの種類
1. レキシカル環境
2. 世界の状態
- スペシャル変数の値
- データ構造の内容
- Lisp外部の状態
- etc...

11.2 with-系マクロ
- コンテキスト生成マクロの名前は with- で始めることが多い
- unwind-protect
- 複雑なマクロは、関数とマクロの組み合わせで書く方が実用的
# dynamic-extent宣言ってなに??
# あとで読む: Common Lisp のスコープとエクステント (PDF)

11.3 条件付き評価
- 定石のうち、明確なものと効率的なものとの選択に直面したときに、
前者を後者に変換するマクロを書く事で、切り抜けられる

11.4 反復
- 本体となる指揮を執って、それを反復評価するオペレータ
=> マクロでのみ表現可能

11.5 複数の値にわたる反復
# ちょっとでかいマクロが多くて、あまりついていけなかった・・・
# 要復習

11.6 マクロの必要性
- 引数をクロージャで括って、評価から保護する方法があるよ
* でも、マクロで書いた方がすっきりする場合多数



On Lisp
Paul Graham

4274066371
オーム社 2007-03
売り上げランキング : 82240
おすすめ平均 star

Amazonで詳しく見る
by G-Tools

by fkmn | 2009-11-20 19:27 | 一人読書会
On Lisp 第10章 マクロのその他の落とし穴
 評価の順番が問題になる例がヤバい。こんなのに遭遇したら、かなりの時間を取られそう。
 副作用と再帰に関しては、マクロ展開の結果がイメージできていれば、避けるのはそんなに難しくない気がする。

10.2 評価の順番
- 評価の順番が問題になる例
(defmacro for ((var start stop) &body body)
(let ((gstop (gensym)))
`(do ((,gstop ,stop)
(,var ,start (1+ ,var)))
((> ,var ,gstop))
,@body)))

(let ((x 1))
(for (i x (setq x 13))
(printc i)))
;=> 13
; NIL

stop "(setq x 13)" の副作用で、ループの初期値が 13 になってしまう。
# うーん、このハマリ方はわかりづらい・・・

10.3 マクロ展開関数の副作用
- 展開を行うコードは引数として渡された式にのみ依存すべきで、
値を返す他には周囲の世界に影響しようとすべきではない。
# この原則が重要そう。
# これさえ守っておけば、上の例のような問題は起きないはず。

10.4 再帰
- 末尾再帰関数は、反復形に変換してマクロのひな形に使う事が容易
; 末尾再帰関数
(defun ntha (n lst)
(if (= n 0)
(car lst)
(nsta (- n 1) (cdr lst))))

; 反復形に変換したマクロ
(defmacro nthc (n lst)
`(do ((n2 ,n (1- n2))
(lst2 ,lst (cdr lst2)))
((= n2 0) (car lst2))))


- マクロの引数そのものについての再帰は可能 (引数を無限に重ねる事はできない)
- マクロ引数の値に対する再帰は不可能 (無限ループ!)


On Lisp
Paul Graham

4274066371
オーム社 2007-03
売り上げランキング : 82240
おすすめ平均 star

Amazonで詳しく見る
by G-Tools

by fkmn | 2009-11-17 23:55 | 一人読書会
On Lisp 第9章 変数捕捉
 慣れるまでは、マクロを使う際に変数名の衝突ではまりそうで怖い。とりあえず、gensym 使っておけば大丈夫っぽく思えるけど、どうなんだろ。
 それから、Common Lisp の defmacro と Scheme の「健全なマクロ」の違いについてよくわかってないので、後で勉強する。

9.4 適切な名前によって捕捉を避ける
- Common Lisp のグローバル変数には、
先頭と末尾にアスタリスクがつく名前を付けるのが伝統
(例) *package*

9.5 事前評価によって捕捉を避ける
- 危険のある引数を、マクロ展開で作られる束縛よりも外で評価する。
=> 例えば、マクロを let で始める

9.6 Gensym によって捕捉を避ける
- 捕捉されうるシンボルを gensym で置き換える
<= マクロの変数捕捉を避ける確実な方法

9.7 パッケージによって捕捉を避ける
# パッケージについて:
# - defpackgage でパッケージを定義
# - in-package でカレントパッケージを指定、
#
# 参考: パッケージを作りたい
# シンボルとパッケージ

9.8 その他の名前空間に置ける捕捉
- do は暗黙のうちに、nil という名前のブロックに囲まれる
(block nil
(list 'a
(do ((x 1 (1+ x)))
(nil)
(if (> x 5)
(return-from nil x)
(princ x)))))
;=> (A 6)
* 外側で明示的に指定されている nil ブロックから抜けているつもりが、
暗黙に作られた do のすぐ外の nil ブロックに捕まってしまい、
結果として評価値が (A 6) になってしまっている。

(block foo
(list 'a
(do ((x 1 (1+ x)))
(nil)
(if (> x 5)
(return-from foo x)
(princ x)))))
;=> 6
* 外側のブロックを nil 以外の名前にすれば、無事に抜けられる

(block nil
(list 'a
(do ((x 1 (1+ x)))
(nil)
(if (> x 5)
(return x)
(princ x)))))
;=> (A 6)
* return は、暗黙的に作られた nil ブロックから抜ける


On Lisp
Paul Graham

4274066371
オーム社 2007-03
売り上げランキング : 82240
おすすめ平均 star

Amazonで詳しく見る
by G-Tools

by fkmn | 2009-11-15 23:55 | 一人読書会
On Lisp 第8章 いつマクロを使うべきか
マクロを使う際の注意点について。
この辺は、実際に使って経験を積まないと分からない (実感できない) 部分も多いだろうなぁ。

基本的には関数を使うべき。マクロが必要なときのみ、それを使う。

8.1 他の手段では不可能なとき
- 1. 変形, 引数等の変形が必要な場合
2. 変数束縛, レキシカルな束縛を変更する場合
3. 条件分岐による評価, 引数を特定条件下でのみ評価する場合
4. 複数回の評価, 引数を繰り返し評価する場合
5. 呼び出し側環境を利用する, 呼び出し側のコンテキストの変数等を利用する場合
* ただし、あまり望ましい使用方法ではない
6. 新しい環境を包み込む
7. 関数呼び出しを節約する
* コンパイル後のコードではマクロ呼び出しに関わるオーバーヘッドがない

8.2 マクロと関数どちらが良い?
- マクロの長所
1. コンパイル時の計算
2. Lisp との密な統合
3. 関数呼び出しの節約

- マクロの短所
1. 関数はデータだが、マクロはコンパイラへの指示に近い
2. ソースコードの明確さ (が失われる)
3. 実行時の明確さ (が失われる)
4. 再帰 (が関数のときほど簡単ではない)


On Lisp
Paul Graham

4274066371
オーム社 2007-03
売り上げランキング : 82240
おすすめ平均 star

Amazonで詳しく見る
by G-Tools

by fkmn | 2009-11-12 23:55 | 一人読書会


とあるWebアプリケーションエンジニアの日記

by fkmn
カテゴリ
以前の記事
ブログパーツ
リンク
検索
タグ
最新のコメント
最新のトラックバック
プログラミングが「出来る..
from とりあえず9JP?
Genographic ..
from ナンジャモンジャ
ジュセリーノ
from ありの出来事
くちこみブログ集(ライフ..
from くちこみブログ集(ライフ)(..
以降、丁寧語で行こう!
from エッセイ的な何か
おすすめキーワード(PR)
ファン
XML | ATOM

skin by excite

fkmnの最近読んだ本 フィードメーター - フッ君の日常 あわせて読みたい AX