Search code examples
schememit-scheme

is it possible to implement "define-macro" in mit-scheme


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?


Solution

  • 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 ...))