问题描述
我有一个包含两个元素子列表的列表,它们将在程序过程中发生变化和增长.我想编写一个宏,它需要一个键并动态生成一个 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
感谢任何提示和评论.
推荐答案
你不需要宏来做你想做的事:使用函数.
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))
您当然希望保持匹配排序.
You want to keep the matches sorted of course.
如果你想延迟表单的执行,那么你可以这样做(这也涉及对类型进行排序):
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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!