マクロを知る
目的と経緯
マクロを実装するには、マクロを知らなければならない。
知ってみよう。
R5RS
R5RS を読んだがよく分からず。
使ってみないとよく分からないことを悟る
マクロを使ってみる
基本
(define-syntax nil! (syntax-rules () ((_ x) (set! x '()))))
んー。なるほど syntax-rules に元の式→変換後の式を指定するのか。_ という変数が Perl の $_変数 を思い起こさせる。
お題にも上がっている when を書いてみよう。
(define-syntax when (syntax-rules () ((_ pred a b) (if pred (begin a b))))) (define x 3) (when (= x 3) (display "x=3") (display "\n"))
分かってきたよ。ちなみに ... を使えば 0 個を含む任意個の式を表現できるとのこと。
パターンマッチング
(define-syntax incf (syntax-rules () ((_ x) (begin (set! x (+ x 1)) x)) ((_ x i) (begin (set! x (+ x i)) x))))
incf の呼出しパターンによって振る舞いを変えられる。
練習問題の decf
(define-syntax decf (syntax-rules () ((_ x) (begin (set! x (- x 1)) x)) ((_ x dx) (begin (set! x (- x dx)) x)))) (decf x) (display x) (decf x 3) (display x) ;; これはエラー (display (decf x 3))
再帰定義
(define-syntax my-and (syntax-rules () ((_) #t) ((_ e) e) ((_ e1 e2 ...) (if e1 (my-and e2 ...) #f))))
マクロの定義中で、マクロを参照できる。
マクロ解釈の実装が面倒そうだなぁ。(まだ良く分からないけど)
練習問題 let* を実装せよ。
まずは let* -> let がどのような感じだったかを思い出す。
(let* ((a 3) (b (+ a 1))) (p a) (p b))
は、以下のような入れ子の let になります。(let*を教えてくれたのは arino さんだったな。)
(let ((a 3)) (let ((b (+ a 1))) (p a) (p b)))
これを踏まえると
(define-syntax my-let* (syntax-rules () ((_ ((a b)) z ...) (let ((a b)) z ...)) ((_ ((a b) (c d) ...) z ...) (let ((a b)) (my-let* ((c d) ...) z ...)))))
うまくいった。
2個めのパターンマッチングで ... を2ヶ所で使っているけど、どちらがどちらにマッチするルールはどうなっているんだろうか。
出現順?
脈絡ないけど
(define-syntax pp (syntax-rules () ((_ a) (begin (display a) (newline))) ((_ a b ...) (begin (pp a) (pp b ...))))) (pp "hoge" "hige" "huga")
さらに
(define-syntax my-if (syntax-rules (my-then my-else) ((_ a my-then b) (if a b)) ((_ a my-then b my-else c) (if a b c)))) (define y 4) (my-if (= y 3) my-then (pp "3") my-else (pp "not 3"))
楽しくなってきた!
局所的なマクロ
(let-syntax ((hello (syntax-rules () ((_ a) (pp "hello" a))))) (hello "higepon"))