Saturday 3 November 2012

MathP and Macros

MathP and macros can be used together a fair bit. I've added a 'math-macro' capability to do custom parsing within MathP input, but you can write macros within MathP (as of version 1.11). I've added direct support for backquote (which has been tested in Corman Common Lisp). Here are some examples of how it all works:

Math-Macro

Macros that use structure in a way that conflicts with the mathematical notation of MathP (that's most macros) can define custom parsing rules. Here's the defun math-macro:
(define-math-macro 'defun (fn (maths)
        (multiple-value-bind (args todo) (parse-argument-list (cdr maths));; Skip name
            (push (car maths) *global-callables*);; Register the function (for recursion and later)
            (multiple-value-bind (body todo) (parse-assignment todo)
                (values `((defun ,(car maths) ,args ,@body)) todo)))))

The above shows that the defun math-macro parses the maths (after the defun symbol) as a name, an argument list and an assignment expression. So input maths of '(defun f (x y) x + y z) would be parsed to a list of one form: (defun f (x y) (+ x y)). The remaining maths (the second return value) would be '(z).

The above also shows how parsing is done in MathP. Note that maths is an argument to parsing functions (including the defun parsing function), and that parsing functions return two values. The first is a list of Lisp forms and the second is the maths remaining to be parsed.

But that's really only useful to give existing macros syntax. Let's dive deeper.

Backquote

As of MathP v1.1, it is now possible to use backquote (including nested backquotes etc.) in MathP. Backquote is used extensively in macro definitions, but can also be used outside of macros. We'll look at backquote first, to lay the foundation for MathP macros. Backquotes in Common Lisp are described in Section 2.4.6 of the Hyperspec. I've attempted to preserve it's behaviour but there are differences. First, a backquoted MathP expression gets wrapped in a progn if it needs it. One potential point of confusion is that in MathP, quote will quote list content without parsing it, but backquote parses content. Here are some examples of the similarities and differences:

#M'a[4]; expands to '(aref a 4)
and
#M`a[4]; expands to `(aref a 4)
#M'(1 2 3+4); expands to '(1 2 3 + 4)
but
#M`(1 2 3+4); expands to `(progn 1 2 (+ 3 4))

Backquote inside MathP

Firstly, a math-macro has been defined for defmacro. It has the same syntax as the defun math-macro. Here's a definition of aif like from On Lisp:
#Mdefmacro aif(test then &optional else) `(it=,test if it ,then ,else)

To include a documentation string, just put it and the body into brackets:
#M{defmacro aif(test then &optional else)
   {"Anaphoric if defined in MathP"
    `(it=,test if it ,then ,else)}}


It's also possible to nest backquotes, but writing a macro with nested backquotes is left as an exercise for the reader.

MathP inside Backquote (Backquote across Lisp and MathP)

I've found that the handling of backquote in Corman Common Lisp doesn't make it possible to consistently backquote a form in Lisp, and unquote something inside it from MathP. If you have a better result in another implementation, please leave a comment. For example (and please excuse the contrived-ness):


(defmacro make-more-func (number) `(lambda (n) #M n+,number))

No comments:

Post a Comment