长期以来一直在研究宏观作业,但我们完全陷入困境,我的老师时间有限,截止日期已经超出限制。这是我们解决这个问题的最后一次尝试。
说明如下:
我们将编写一个宏匹配模式,将参数expr与许多参数pattern_i相匹配。 如果成功,则在评估期间使用pattern_i中的自由变量评估body_i。
Expr只应评估一次
示例:
* (match-pattern '((foo bar) foo baz)
((car . car) `(:cons ,car ,car))
((one two three) `(:three ,one ,two ,three)))
(:THREE (FOO BAR) FOO BAZ)
到目前为止我们的策略是这样的:
1
我们计划在宏中用于比较模式的匹配函数。 (也许不完全正确,但你得到了重点)
(defun match (sexpr1 sexpr2)
(cond ((and (consp sexpr1) (consp sexpr2))
(and (match (first sexpr1) (first sexpr2))
(match (rest sexpr1) (rest sexpr2))))
((and (atom sexpr1) (atom sexpr2))
t)
(t nil)))
2
我们想要针对expr循环所有模式,并通过将它们传递给我们的匹配函数,我们将返回true或nil。如果是真的,我们将expr分配给模式的主体。
(defmacro match-pattern (sexpr &body body)
(cond
((match sexpr (car (car body))) (print "sexpr shall match with body here"))
((null (cdr body)) nil)
(t `(match-pattern sexpr ,@(cdr body)))))
3
不知道匹配是如何工作的,我们尝试将#mapcar与匿名lambda函数结合使用,但没有比这更进一步。
这似乎是一种合理的方法吗? 报价有很多问题。在描述的例子中有关于expr的引用但不是关于身体模式中的引用,为什么会这样? 为什么会出现这样的问题:身体有三个缺点?
答案 0 :(得分:3)
解决此问题的常见方法如下:
将匹配器扩展为更精细的中间表示,例如,模式和操作对(('a b) b)
已转换为(match-action V1 (match-cons (match-quote a) (match-cons (match-bind b) (match-nil))) (progn b))
。
实现一个更简单的宏match-action
,它将命令树展开为一系列嵌套绑定和检查。每次失败的检查都会返回特殊的失败值。例如,(match-action V1 (match-bind x) x)
已扩展为(let ((x V1)) x)
,或(match-action V1 (match-cons (match-bind a) (match-bind b)) (cons b a))
已扩展为(if (listp V1) (let ((V2 (car V1)) (V3 (cdr V1)) (a V2) (b V3)) (cons b a)) match-failure)
。请注意,match-bind
命令必须检查其参数是否已在上下文中,并且在这种情况下,它应转换为结构相等性检查。
现在,实现match
宏是微不足道的 - 引入一个新变量(带gensym
),将其绑定到表达式的值,并按顺序应用匹配器,除非匹配器返回与match-failure
不同的东西。
我希望你能够实现自己的匹配器。请注意,此方法是可扩展的,您可以添加更复杂的模式,如省略号,函数匹配器,正则表达式等。
答案 1 :(得分:1)
我记得回答了一个模式匹配问题,但是以一种功能性方式:compare lists using wild cards。以下答案保留了答案的背景。
您的宏可以执行以下操作:
expr
评估为变量; (pattern &body body)
子句展开为调用cmp
(或您的match
),将结果保存在变量中,如果不是nil
,则运行{{1} }}。示例:
body
鉴于此,您仍然需要:
(defmacro match-pattern (expr &rest clauses)
(let ((expr-var (make-symbol (symbol-name '#:expr)))
(bindings-var (make-symbol (symbol-name '#:bindings))))
`(let ((,expr-var ,expr)
(,bindings-var nil))
(declare (ignorable ,expr-var))
(cond ,@(mapcar #'(lambda (clause)
(destructuring-bind (pattern &body body)
clause
`((setf ,bindings-var (cmp ,expr-var ,pattern))
(let (,@(mapcar #'(lambda (var)
`(,var (cdr (assoc ',var ,bindings-var))))
(pattern-vars pattern)))
,@body))))
clauses)))))
; pattern-vars
(或您的cmp
)以返回alist
变量绑定而不仅仅match
。