2

After reading this page. I find it hard to memorize how to use define-syntax in place of define-macro, so I want to implement define-macro (or at least find some equivalent) in mit-scheme.

Here is my (problematic) implementation:

(define-syntax define-macro
  (rsc-macro-transformer
    (let ((xfmr (lambda (macro-name macro-body)
      (list 'define-syntax macro-name
        (list 'rsc-macro-transformer
          (let ((m-xfmr macro-body))
            (lambda (e r)
              (apply m-xfmr (cdr e)))))))))
      (lambda (e r)
        (apply xfmr (cdr e))))))

(define-macro my-when
  (lambda (test . branch)
    (list 'if test (cons 'begin branch))))

(my-when #t
  (begin
    (display "True")
    (newline)))

And the REPL complained:

;The object (lambda (test . branch) (list (quote if) test (cons (quote begin) branch))) is not applicable.

I'm new to scheme and have no idea about what is wrong, can someone help me out?

2 Answers 2

7

Firstly, you should learn to use quasiquotation, so your macro is easier to read. Like this:

(define-macro (my-when test . branch)
  `(if ,test
     (begin ,@branch)))

More seriously, though, this is pretty easy to write using syntax-rules, and you really should vastly prefer it over define-macro.

(define-syntax-rule (my-when test branch ...)
  (if test
    (begin branch ...)))

Oh, you haven't seen define-syntax-rule before? It's a simple macro you can use for writing a one-clause define-syntax macro, and it's defined so:

(define-syntax define-syntax-rule
  (syntax-rules ()
    ((define-syntax-rule (name . pattern) template)
     (define-syntax name
       (syntax-rules ()
         ((name . pattern) template))))))

Notice how, using define-syntax-rule, simple macros become really, really easy to write. Here's another example:

(define-syntax-rule (let ((name value) ...)
                      expr ...)
  ((lambda (name ...)
     expr ...)
   value ...))
Sign up to request clarification or add additional context in comments.

5 Comments

+1, especially to the advice to simply use syntax-rules. It's hygienic, which can save you from having to debug some really hideous bugs later on.
Thanks, I haven't heard of define-syntax-rule before. It does simplify the code. But here I encountered a problem: when I attempted to eval (define-syntax-rule (my-when test branch) (if test (begin branch))), it said ;Unbound variable: test. BTW, my scheme version is mit-scheme 9.0.1
@Javran Did you run the (define-syntax define-syntax-rule ...) thing I pasted? You need to do that first.
Sorry, I thought it had already been defined. Now it works, thank you in advance!
@Javran In some Scheme implementations, like Racket and Guile, it's already defined. In MIT Scheme, I guess that's not the case. :-) Anyway, glad that helped. :-)
3

If you really need define-macro semantics, you can get a reasonable approximation in mit-scheme like so:

(define-syntax define-macro
  (syntax-rules ()
    ((define-macro (name . args) body ...)
     (define-syntax name
       (rsc-macro-transformer
         (let ((transformer (lambda args body ...)))
           (lambda (exp env)
              (apply transformer (cdr exp)))))))))

You could then define my-when as:

(define-macro (my-when test . branch)
  `(if ,test (begin ,@branch)))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.