Macros 如何在lisp中使用if形式定义递归cond宏?

Macros 如何在lisp中使用if形式定义递归cond宏?,macros,scheme,lisp,common-lisp,guile,Macros,Scheme,Lisp,Common Lisp,Guile,我想使用lisp宏与if一起实现cond,这是我的尝试: (define-macro (cond . clauses) (if (pair? clauses) (let ((first (car clauses)) (rest (cdr clauses))) `(if ,(car first) (begin ,@(cdr first)) ,(if (equal? (caar

我想使用lisp宏与if一起实现cond,这是我的尝试:

(define-macro (cond . clauses)
  (if (pair? clauses)
      (let ((first (car clauses)) (rest (cdr clauses)))
         `(if ,(car first)
              (begin
                 ,@(cdr first))
              ,(if (equal? (caar rest) 'else)
                  ',(cadr rest)
                   `(cond ,rest))))))
但它不起作用,当我用以下代码调用它时:

(cond ((= 1 0) (display "hello"))
      ((= 1 1) (display "world"))
      (else
        (display "foo")))
我得到了这个错误:

ERROR: In procedure car: Wrong type argument in position 1 (expecting pair): ()

我为什么会出现这个错误以及如何修复它?我更喜欢用lisp宏来解决问题。

大多数Scheme程序员,包括我自己,都不喜欢使用define宏,因为它完全不卫生。我不知道你为什么喜欢用它们。考虑到这一点,我不会自己编写任何define宏,我在Femtolisp中摸索了一个类似于方案的实现,它也不使用卫生宏:

希望它对你有用

如果您喜欢的不是老式的不卫生的宏,而是一个允许您在原始格式中处理传入表单的宏系统,那么许多Scheme实现提供了一个显式重命名ER宏系统,它允许您直接操作表单,并且仍然允许您维护卫生,正如其名称所暗示的那样,显式重命名任何应受到宏调用站点保护的标识符。这是:


主要的Scheme实现通常分为两大阵营,它们使用的是低级宏:语法大小写和显式重命名。Racket、Chez Scheme、Guile等。语法用例。CHICKEN、MIT方案、Chibi方案等使用显式重命名。因此,您将无法在Guile中使用上面的显式重命名版本,因为它位于syntax case阵营中。

这是一个有效的Lisp版本:

(defmacro mycond (&rest clauses)
  (if (consp clauses)
      (destructuring-bind ((pred . forms) . rest-clauses) clauses
        `(if ,pred
             (progn ,@forms)
           ,(if (and (consp rest-clauses)
                     (eq (caar rest-clauses) 't))
                `(progn ,@(cdar rest-clauses))
              `(mycond ,@rest-clauses))))
    nil))
您可以看到已修复了四个错误:

逗号不在反引号内 其余的条款需要拼接在一起 默认的T子句需要插入代码 不要覆盖内置条件 扩展示例:

CL-USER 67 > (walker:walk-form '(mycond ((= 1 0) (write "hello"))
                                        ((= 1 1) (write "world"))
                                        (t       (write "foo"))))

(IF (= 1 0)
    (PROGN (WRITE "hello"))
  (IF (= 1 1)
      (PROGN (WRITE "world"))
    (PROGN (WRITE "foo"))))
稍微简单一点的版本:

(defmacro mycond (&rest clauses)
  (if (consp clauses)
      (destructuring-bind ((pred . forms) . rest-clauses) clauses
        (if (eq pred t)
            `(progn ,@forms)
          `(if ,pred
               (progn ,@forms)
             (mycond ,@rest-clauses))))
    nil))

我已经在guile scheme中重新创建了您的解决方案,非常感谢。scheme和common lisp是两种不同的lisp语言,lisp通常被理解为是lisp1.5的直系后代CL的同义词。guile是一个r5rs方案,与CommonLisp无关。你想要的答案不是guile吗?@Sylwester我想用lisp macros或guile scheme获得答案,因为我可以在scheme中重写用CL编写的宏。我把这个问题标为common lisp,因为我想得到更多答案。
CL-USER 67 > (walker:walk-form '(mycond ((= 1 0) (write "hello"))
                                        ((= 1 1) (write "world"))
                                        (t       (write "foo"))))

(IF (= 1 0)
    (PROGN (WRITE "hello"))
  (IF (= 1 1)
      (PROGN (WRITE "world"))
    (PROGN (WRITE "foo"))))
(defmacro mycond (&rest clauses)
  (if (consp clauses)
      (destructuring-bind ((pred . forms) . rest-clauses) clauses
        (if (eq pred t)
            `(progn ,@forms)
          `(if ,pred
               (progn ,@forms)
             (mycond ,@rest-clauses))))
    nil))