Большинство программистов Схемы, включая меня, не любят использовать define-macro
, потому что это абсолютно негигиенично. Я понятия не имею, почему вы предпочитаете их использовать. Имея это в виде (что я бы не писать никаких define-macro
макросов себя), я пошарил Femtolisp (схему подобную реализации, также не использует гигиенические макросы) для its implementation of cond
:
(define-macro (cond . clauses)
(define (cond-clauses->if lst)
(if (atom? lst)
#f
(let ((clause (car lst)))
(if (or (eq? (car clause) 'else)
(eq? (car clause) #t))
(if (null? (cdr clause))
(car clause)
(cons 'begin (cdr clause)))
(if (null? (cdr clause))
; test by itself
(list 'or
(car clause)
(cond-clauses->if (cdr lst)))
; test => expression
(if (eq? (cadr clause) '=>)
(if (1arg-lambda? (caddr clause))
; test => (lambda (x) ...)
(let ((var (caadr (caddr clause))))
`(let ((,var ,(car clause)))
(if ,var ,(cons 'begin (cddr (caddr clause)))
,(cond-clauses->if (cdr lst)))))
; test => proc
(let ((b (gensym)))
`(let ((,b ,(car clause)))
(if ,b
(,(caddr clause) ,b)
,(cond-clauses->if (cdr lst))))))
(list 'if
(car clause)
(cons 'begin (cdr clause))
(cond-clauses->if (cdr lst)))))))))
(cond-clauses->if clauses))
Надеется, что это работает для Вас!
Если то, что вы предпочитаете не старый стиль антисанитарных макросы, а просто система макросов, что позволяет играть с входящей формой в сырье, многих реализациях Scheme обеспечивают явное переименование (ER) макросистему, который позволяет вам напрямую манипулировать формами и по-прежнему позволяет поддерживать гигиену (как следует из названия), явно переименовывая любые идентификаторы, которые должны быть защищены от затенения на сайте вызова макросов. Вот Chibi Scheme's implementation of cond
:
(define-syntax cond
(er-macro-transformer
(lambda (expr rename compare)
(if (null? (cdr expr))
(if #f #f)
((lambda (cl)
(if (compare (rename 'else) (car cl))
(if (pair? (cddr expr))
(error "non-final else in cond" expr)
(cons (rename 'begin) (cdr cl)))
(if (if (null? (cdr cl)) #t (compare (rename '=>) (cadr cl)))
(list (list (rename 'lambda) (list (rename 'tmp))
(list (rename 'if) (rename 'tmp)
(if (null? (cdr cl))
(rename 'tmp)
(list (car (cddr cl)) (rename 'tmp)))
(cons (rename 'cond) (cddr expr))))
(car cl))
(list (rename 'if)
(car cl)
(cons (rename 'begin) (cdr cl))
(cons (rename 'cond) (cddr expr))))))
(cadr expr))))))
реализации Основные Схема, как правило, разделены на два лагеря с точки зрения того, что они используют для макросов низкого уровня: syntax-case
и явного переименования. Racket, Chez Scheme, Guile и т. Д. Используют syntax-case
. CHICKEN, MIT Scheme, Chibi Scheme и т. Д. Используют явное переименование. Таким образом, вы не сможете использовать явную версию переименования выше в Guile, потому что она находится в лагере syntax-case
.
схема и общего сюсюкать два разных лисповские языков и сюсюкать часто понимается как синоним CL, который является прямым потомком lisp1.5.guile - это схема r5rs и не имеет ничего общего с общим lisp. Вы после ответов на других языках, кроме хитрости? – Sylwester
@Sylwester Я хотел получить ответ в lisp macros ether CL или guile схеме, так как я могу переписать макрос в схеме, когда он написан в CL. Я отмечаю общий вопрос, потому что хочу получить больше ответов. – jcubic