Macros 如何在lisp中使用if形式定义递归cond宏?
我想使用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
(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))