3imp 読んでみる (5)
送別会は酒が出ず、早々に終了したので帰宅後、作業再開。
recur の define-syntax を検討。まず rec のソレから検証か。ええと
(rec var exp)
は
(let ([var '()]) (set! var exp))
と等価とある。例示されている
(rec count (lambda (x) (if (null? x) 0 (+ (count (cdr x)) 1))))
は
(let ([count '()]) (set! count (lambda (x) (if (null? x) 0 (+ (count (cdr x)) 1)))))
define-syntax 的にはこう書けば良いのでしょうか。
(define-syntax rec (syntax-rules () ((_ a b) (let ([a '()]) (set! a b)))))
試験。
gosh> (define-syntax rec (syntax-rules () ((_ a b) (let ([a '()]) (set! a b))))) #<undef> gosh> ((rec count (lambda (x) (if (null? x) 0 (+ (count (cdr x)) 1)))) '(1 2 3)) 3 gosh>
次は recur ですが
(recur f ([var init ...) exp ...))
は
((rec f (lambda (var ...) exp ...)) init ...)
と等価との事。こうすれば良いのかな
(define-syntax recur (syntax-rules () ((_ f ([v i] ...) e ...) ((rec f (lambda (v ...) e ...)) i))))
REPL に吸わせてみた。
gosh> (define-syntax recur (syntax-rules () ((_ f ([v i] ...) e ...) ((rec f (lambda (v ...) e ...)) i)))) *** ERROR: Compile Error: recur: Pattern variable i is used in wrong level: ((rec f (lambda (v |...|) e |...|)) i) "(stdin)":10:(define-syntax recur (syntax-rules ( ... Stack Trace: _______________________________________ gosh>
むが。こうか。
(define-syntax recur (syntax-rules () ((_ f ([v i] ...) e ...) ((rec f (lambda (v ...) e ...)) i ...))))
REPL に吸わせたら
gosh> (define-syntax recur (syntax-rules () ((_ f ([v i] ...) e ...) ((rec f (lambda (v ...) e ...)) i ...)))) #<undef> gosh> (recur count ([x '(a b c d e)]) (if (null? x) 0 (+ (count (cdr x)) 1))) 5 gosh>
ええのかなぁ。とりあえず元に戻ろう。
Assembly Code
そういえば _sets next expression x_ なソレですが x を next expression にセット、という意味で OK かなぁ。VM 見てると record-case というのもあるな。28p に定義が記述されている。
(record-case exp1 [key vars exp2 ...] . . . [else exp3 ...])
は
(let ([r exp1]) (cond [(eq? (car r) 'key) (record vars (cdr r) exp2 ...)] . . . [else exp3 ...]))
になるそうな。ちょっとこれ define-syntax 方面に行ってしまうとハマるので別途で。
- (test then else) : accumulator を test し accumulator が nonnull だったら next expression に then をセット、そうでなければ else を next expression にセット
- (assign var x) : current environment に束縛されている var に accumulator の値をセットして next expression に x をセット
- (conti x) : current stack から継続を生成し accumulator に置いて next expression に x をセット。
- (nuate s var) : s を current stack に、var の値を current environment から探して accumulator に、next expression に (return) をセット
- (frame x ret) : current environment、current rib と next expression が ret な新しいフレームを生成。このフレームに current stack を追加して current rib は空リストをセットし、next expression を x に。(微妙
- (argument x) : accumulator の値を current rib に追加して x を next expression にセット (VM のコードを見るに current rib はリストになっている模様
- (apply) : accumulator にあるクロージャを apply (current rib は引数??) する。ここ、ちょっと長いので VM の定義を見てみると以下
[apply () (record a (body e vars) (VM a body (extend e vars r) '() s))]
record の定義は 27p にある。apply しとります。
(redord (var ...) val exp ...)
は
(apply (lambda (var ...) exp ...) val)
だそうな。サンプルとしては
(lambda (x) (record (a b c) x (list c b a)))
みたいなソレ。こんなカンジが
((lambda (x) (record (a b c) x (list c b a))) '(1 2 3))
こんな感じで評価されるはず
(apply (lambda (a b c) (list c b a)) '(1 2 3))
これは define-syntax なナニは簡単そげな気がしますがスルーで別途。と言いつつ record-case もチェック
(record-case exp1 [key vars exp2 ...] . . . [else exp3 ...])
は以下と等価
(let ([r exp1]) (cond [(eq? (car r) 'key) (record vars (cdr r) exp2 ...)] . . . [else exp3 ...]))
これはツライ。VM のコードは別途じっくりってコトで元に戻ります。って英語は英語で微妙なんだけどなぁ。