Last active
August 29, 2015 13:56
-
-
Save guicho271828/9306518 to your computer and use it in GitHub Desktop.
non-recursive-struggling-macroexpansion.lisp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(require :cl21) | |
(in-package :cl21-user) | |
;; C は何らかの、処理系独特の最適化が行われる | |
;; 関数の例だと考えてください | |
(defun C-fun (x) | |
(print (* 10 x))) | |
(defmacro C (x &environment env) | |
(if (symbolp x) | |
(progn | |
(print (multiple-value-list (variable-information x env))) | |
`(c-fun ,x)) | |
(progn | |
(print :normal) | |
`(c-fun ,x)))) | |
(defun test1 () | |
(C 1)) | |
(defun test2 () | |
(let ((x 1)) | |
(C x))) | |
(defun test3 () | |
(let ((x 1)) | |
(declare (type number x)) | |
(C x))) | |
;; test1 ... test 3 をコンパイルするとメッセージがでてきます | |
(defmacro B (var &body body &environment env) | |
`(let ((,var 5)) | |
(declare (type number ,var)) | |
,@body)) | |
(defmacro A (body &environment env) | |
`(progn | |
,body)) | |
;; test3のコンパイル結果と同じはず | |
(defun test4 () | |
(A (B x (C x)))) | |
;; 再定義 | |
(defmacro A (body &environment env) | |
`(progn | |
,(macroexpand body env))) | |
;; 同じはず | |
(defun test5 () | |
(A (B x (C x)))) | |
;; 再定義: C の中で x の型が fixnum でないとエラーを投げるようにする | |
(defmacro C (x &environment env) | |
(if (symbolp x) | |
(progn | |
(if (eq 'fixnum | |
(cdr | |
(assoc 'type | |
(third | |
(multiple-value-list | |
(variable-information x env)))))) | |
(progn (print :yes-fixnum) `(c-fun ,x)) | |
(progn (cerror "無視する?" "整数でない") `(c-fun ,x)))) | |
(progn | |
(print :normal) | |
`(c-fun ,x)))) | |
;; コンパイル成功 | |
(defun test6 () | |
(let ((x 5)) | |
(declare (fixnum x)) | |
(C x))) | |
;; コンパイル失敗 | |
(defun test7 () | |
(let ((x 5)) | |
(C x))) | |
;; 再定義: Aの中でこのエラーをキャッチできるか? | |
(defmacro A (body &environment env) | |
`(progn | |
,(block nil | |
(handler-bind ((error (lambda (c) | |
(print :handled) | |
(continue c)))) | |
(macroexpand body env))))) | |
;; 一階層ならできる | |
(defun test8 () | |
(let ((x 5)) | |
(A (C x)))) | |
;; 二階層になるとダメ | |
(defun test9 () | |
(A (B x (C x)))) | |
;; さて、じゃあBでもmacroexpandを呼べばいい? | |
(defmacro B (var &body body &environment env) | |
`(let ((,var 5)) | |
(declare (type number ,var)) | |
,@(map ;; (lambda (form) | |
;; (macroexpand form env)) | |
^(macroexpand _ env) | |
body))) | |
;; たしかにok。 | |
(defun test10 () | |
(A (B x (C x)))) | |
;; でも、Bがいつも自分のマクロ、つまり自分で再定義できるマクロかどうかはわからない! | |
;; しかも、Cは数カッコ分離れた内側にいるかもしれない | |
(defun test10 () | |
(A (somelib-macro (implementation-specific-macro (somelib-macro2 (C x))))))) | |
;; somelib-macro,implementation-specific-macro,somelib-macro2 このすべてが | |
;; 中で同じようにmacroexpandを呼んでくれるとは限らない。 |
むずかしー
^
使って見ました
ちょっと家族迎えに行きます。車の中でもうすこし考えます。
別件ですけど 上の例でのhandler-bindのlambdaを最初から^で書けるかどうか迷いませんか?
cを2回参照すると駄目で1回なら大丈夫…
そうかもしれませんね。
二回使える方が便利か、それとも二つ引数をとれるほうが便利か・・・
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
lambda かくのが癖になってますね;;