Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guicho271828/9306518 to your computer and use it in GitHub Desktop.
Save guicho271828/9306518 to your computer and use it in GitHub Desktop.
non-recursive-struggling-macroexpansion.lisp
(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を呼んでくれるとは限らない。
@snmsts
Copy link

snmsts commented Mar 2, 2014

(defmacro B (var &body body &environment env)
  `(let ((,var 5))
     (declare (type fixnum ,var))
     ,@(map ^(macroexpand-1 _ env) body)))

@guicho271828
Copy link
Author

lambda かくのが癖になってますね;;

@snmsts
Copy link

snmsts commented Mar 2, 2014

むずかしー

@guicho271828
Copy link
Author

^使って見ました

@guicho271828
Copy link
Author

ちょっと家族迎えに行きます。車の中でもうすこし考えます。

@snmsts
Copy link

snmsts commented Mar 2, 2014

別件ですけど 上の例でのhandler-bindのlambdaを最初から^で書けるかどうか迷いませんか?
cを2回参照すると駄目で1回なら大丈夫…

@guicho271828
Copy link
Author

そうかもしれませんね。

@guicho271828
Copy link
Author

二回使える方が便利か、それとも二つ引数をとれるほうが便利か・・・

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment