2008-01-04
■ [biwascheme] let*の変換
let*はletのネストに変換できる。*1
(let* ((a 1) (b a)) (print a) (+ a b)) ↓ (let ((a 1)) (let ((b a)) (print a) (+ a b)))
ということで、
- バインディングを最後から順番に取って、
- body = (let (bind) (body)) とする
という操作を繰り返せばよい。
…のだが、biwaschemeではbodyに複数の式を許しているので、最初だけ特別扱い(Pairで包まない)しなければならない。
var ret = null; binds.to_array().reverse().each(function(bind){ ret = new Pair(Sym("let"), new Pair(new Pair(bind, nil), ret == null ? body : new Pair(ret, nil))); }) return ret;
というのでちょっと悩んだ。
再帰的に書けばこんな罠にははまらないっぽいんだが。
syntax-rulesで書いてみた例。
(define-syntax letstar (syntax-rules () ((letstar ((var val)) body ...) (let ((var val)) body ...)) ((letstar ((var val) (var2 val2) ...) body ...) (let ((var val)) (let* ((var2 val2) ...) body ...))))) (print (let ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) (list x y z))))
*1 letは最終的にlambdaに変換できるので、let*から直接lambdaに変換しても良いと思う
■ [scheme] syntax-rulesでdefine-structをつくる
去年書き忘れた記事。
MzSchemeにはdefine-structという構文(Common Lispのdefstructみたいなもの)があるらしくて、 Gaucheにもあったらいいなぁと思ったので作ってみた。
…とさらっと書いたけど非常に苦労しましたw
;; string-appendのシンボル版 (define (symbol-append . syms) (string->symbol (apply string-append (map symbol->string syms)))) ;; define-structという構文を定義 (define-syntax define-struct (syntax-rules () ((define-struct name props) (eval `(begin (define-class ,(symbol-append '< 'name '>) () ,(map (lambda (sym) `(,sym :init-keyword ,(make-keyword sym) :accessor ,(symbol-append sym '-of- 'name))) 'props)) ,@(map (lambda (sym) `(define-method ,(symbol-append 'name '- sym '-set!) ((obj ,(symbol-append '< 'name '>)) ,sym) (slot-set! obj ',sym ,sym))) 'props)) (interaction-environment)))))
使用例。
(define-struct book (title jp-title)) (let1 bk (make <book> :title "SICP") (print (title-of-book bk)) (book-jp-title-set! bk "(前略)構造と解釈") (print (jp-title-of-book bk)) )
はっきり言ってsyntax-rules使う意味がない(パターンマッチ使ってない)。 define-macroで書き直してみようかと思ったけど気力が尽きたので省略。 あとevalをなんとかしたかったけど無理だった。
先輩はevalなし(syntax-rulesだけ)でできるって言うんだけどさ、無理じゃね? syntax-rulesじゃマクロ展開時にsymbol-appendを実行することができないんだし。
syntax-rulesでsymbol-appendが実装できれば別だけど…、いくらチューリング完全と言っても、 それはリスト操作についてであって、symbol->stringが実装できるわけではない。よね。