在Common Lisp中使用宏生成TYPECASE [英] Generate TYPECASE with macro in Common Lisp
问题描述
我有两个元素子列表的列表,它们在程序的过程中会不断变化.我想编写一个需要一个键并动态生成 case
的宏,例如:
I have a list of two element sublists which will change and grow in the course of the program. I want to write a macro which takes a key and generates a case
dynamically like:
;; This is the List for saving CASE clauses
(setf l '((number 2) (symbol 3)))
;; and i want to have the following expansion
(typecase 'y
(number 2)
(symbol 3))
我可以有一个仅引用全局 l
的宏:
I could have a macro which only refers to the global l
:
(defmacro m (x)
`(typecase ,x ,@l))
可以正确展开
(m 'y) ;expands to (TYPECASE 'Y (number 2) (symbol 3))
但是我怎么能为列表 l
的参数写宏,以便它也可以与其他列表一起使用?
But how can i write the macro with a parameter for the list l
so that it would work with other lists as well?
;; A macro which should generate the case based on the above list
(defmacro m (x l)
`(typecase ,x ,@l))
这不起作用,因为参数列表中的 l
是一个符号,并且对(m'yl)
的调用将扩展为(TYPECASE'Y.L)
.
This doesn't work since l
in the arguments list i a symbol and a call to (m 'y l)
will expand to (TYPECASE 'Y . L)
.
想要坚持 typecase
机制,我的解决方法如下:
Wanting to adhere to typecase
mechanism, my workaround was as follows:
(setf types-x '(((integer 0 *) 38)
((eql neli) "Neli in X")
(symbol 39))
)
(setf types-y '(((eql neli) "Neli in Y")
((array bit *) "A Bit Vector")))
(defmacro m (x types-id)
(case types-id
(:x `(typecase ,x ,@types-x))
(:y `(etypecase ,x ,@types-y))))
(m 'neli :x) ;"Neli in X"
(m 'neli :y) ;"Neli in Y"
(m 'foo :x) ;39
任何提示和评论都会受到赞赏.
Any hints and comments is appreciated.
推荐答案
您不需要使用宏即可使用函数.
You don't need a macro for what you're trying to do: use a function.
例如,给定
(defvar *type-matches*
'((float 0)
(number 1)
(t 3)))
然后
(defun type-match (thing &optional (against *type-matches*))
(loop for (type val) in against
when (typep thing type)
return (values val type)
finally (return (values nil nil))))
将事物与类型匹配:
> (type-match 1.0)
0
float
> (type-match 1)
1
number
您希望按类型对变量进行排序,例如:
You want to keep the variables sorted by type, which you can do by, for instance:
(setf *type-matches* (sort *type-matches* #'subtypep :key #'car))
您想让比赛保持理顺.
如果您想延迟表单的执行,则可以执行以下操作(这也涉及对类型进行排序):
If you want to delay the execution of the forms then you can do something like this (this also deals with sorting the types):
(defvar *type-matches*
'())
(defmacro define-type-match (type/spec &body forms)
;; define a type match, optionally in a specified list
(multiple-value-bind (type var)
(etypecase type/spec
(symbol (values type/spec '*type-matches*))
(cons (values (first type/spec) (second type/spec))))
(let ((foundn (gensym "FOUND")))
`(let ((,foundn (assoc ',type ,var :test #'equal)))
(if ,foundn
(setf (cdr ,foundn) (lambda () ,@forms))
(setf ,var (sort (acons ',type (lambda () ,@forms) ,var)
#'subtypep :key #'car)))
',type/spec))))
(defun type-match (thing &optional (against *type-matches*))
(loop for (type . f) in against
when (typep thing type)
return (values (funcall f) type)
finally (return (values nil nil))))
这篇关于在Common Lisp中使用宏生成TYPECASE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!