Macros 公共Lisp宏模式匹配

Macros 公共Lisp宏模式匹配,macros,common-lisp,Macros,Common Lisp,很长一段时间以来,我们一直在为家庭作业编写宏,但我们完全被卡住了,我的老师时间有限,而且截止日期远远超过了限制。这是我们最后一次尝试解决这个问题 说明如下: 我们将编写一个宏匹配模式,该模式将参数expr与多个参数pattern_i相匹配。 如果成功,则在求值期间,将使用模式_i绑定中的自由变量对body_i求值 模式是一个s表达式 它必须完全匹配 无法使用符号引号 Expr只能计算一次 例如: * (match-pattern '((foo bar) foo baz) (

很长一段时间以来,我们一直在为家庭作业编写宏,但我们完全被卡住了,我的老师时间有限,而且截止日期远远超过了限制。这是我们最后一次尝试解决这个问题

说明如下:

我们将编写一个宏匹配模式,该模式将参数expr与多个参数pattern_i相匹配。 如果成功,则在求值期间,将使用模式_i绑定中的自由变量对body_i求值

模式是一个s表达式

它必须完全匹配

无法使用符号引号

Expr只能计算一次

例如:

   * (match-pattern '((foo bar) foo baz)
        ((car . car)     `(:cons ,car ,car))
        ((one two three) `(:three ,one ,two ,three)))

   (:THREE (FOO BAR) FOO BAZ)
(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)))))
到目前为止,我们的策略是:

一,

我们计划在宏中用于比较模式的匹配函数。也许不完全正确,但你明白了

    (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)))
二,

我们希望根据expr循环所有模式,通过将它们传递给我们的match函数,我们将返回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)))))
三,

由于不知道匹配是如何工作的,我们尝试将“mapcar”与匿名lambda函数结合使用,但没有进一步的改进

这似乎是一个合理的方法吗? 在报价方面有很多问题。在描述中的示例中,expr上有一个引号,但正文中的模式中没有,这是为什么?
为什么身体里有三个和三个缺点?

解决这个问题的常见方法如下:

将匹配器扩展为更精细的中间表示形式,例如,模式和动作对“a b b b”被转换为匹配动作V1匹配cons匹配引号a匹配cons匹配绑定b匹配nil程序b

实现一个更简单的宏匹配操作,该操作将命令树展开为一系列嵌套绑定和检查。每个失败检查返回一个特殊的失败值。例如,匹配操作V1匹配绑定x x扩展为let x V1 x,或匹配操作V1匹配cons匹配绑定a匹配绑定b cons b a扩展为if listp V1 let V2 car V1 V3 cdr V1 a V2 b V3 cons b a匹配失败。请注意,match bind命令必须检查其参数是否已经在上下文中,在这种情况下,它应该转换为结构相等性检查

现在,实现match宏很简单——使用gensym引入一个新变量,将其绑定到表达式的值,并按顺序应用匹配器,除非匹配器返回与match failure不同的结果


我希望您能够实现自己的matcher。请注意,此方法是可扩展的,您可以添加更复杂的模式,如省略号、函数匹配器、regexp等。

解决此问题的常见方法如下:

将匹配器扩展为更精细的中间表示形式,例如,模式和动作对“a b b b”被转换为匹配动作V1匹配cons匹配引号a匹配cons匹配绑定b匹配nil程序b

实现一个更简单的宏匹配操作,该操作将命令树展开为一系列嵌套绑定和检查。每个失败检查返回一个特殊的失败值。例如,匹配操作V1匹配绑定x x扩展为let x V1 x,或匹配操作V1匹配cons匹配绑定a匹配绑定b cons b a扩展为if listp V1 let V2 car V1 V3 cdr V1 a V2 b V3 cons b a匹配失败。请注意,match bind命令必须检查其参数是否已经在上下文中,在这种情况下,它应该转换为结构相等性检查

现在,实现match宏很简单——使用gensym引入一个新变量,将其绑定到表达式的值,并按顺序应用匹配器,除非匹配器返回与match failure不同的结果


我希望您能够实现自己的matcher。请注意,这种方法是可扩展的,您可以添加更复杂的模式,如省略号、函数匹配器、regexp等。

我记得回答了一个模式匹配问题,但以函数的方式:。以下答案保留了该答案的上下文

您的宏可以执行以下操作:

将expr计算一次为一个变量; 展开每个pattern&body body子句,调用cmp或您的匹配,将结果保留在一个变量中,如果不是nil,则运行body。 例如:

   * (match-pattern '((foo bar) foo baz)
        ((car . car)     `(:cons ,car ,car))
        ((one two three) `(:three ,one ,two ,three)))

   (:THREE (FOO BAR) FOO BAZ)
(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)))))
鉴于此,您仍然需要:

定义模式变量; 当匹配模式中存在变量时,调整cmp或您的匹配以返回变量绑定的数量,而不仅仅是t。
我记得我回答了一个模式匹配问题,但是以功能性的方式回答的:。以下答案保留了该答案的上下文

您的宏可以执行以下操作:

将expr计算一次为一个变量; 展开每个pattern&body body子句,调用cmp或您的匹配,将结果保留在一个变量中,如果不是nil,则运行body。 例如:

   * (match-pattern '((foo bar) foo baz)
        ((car . car)     `(:cons ,car ,car))
        ((one two three) `(:three ,one ,two ,three)))

   (:THREE (FOO BAR) FOO BAZ)
(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)))))
鉴于此,您仍然需要:

定义模式变量; A. 当匹配模式中存在变量时,dapt cmp或match将返回变量绑定的数量,而不仅仅是t。 @wvxvw,如果您使用just:expr,则在定义宏时会发出警告,在使用宏时会出现错误。但是,如果您的意思是使符号名“:expr”和“:expr”不同,则前者总是创建一个新符号,而后者将在所有宏扩展中重复使用同一符号。@wvxvw,如果您仅使用:expr,则在定义宏时会发出警告,在使用宏时会出现错误。但是,如果您指的是make symbol symbol name':expr和“:expr”之间的区别,则前者总是创建一个新符号,而后者将在所有宏扩展中重用相同的符号。