Hacker News new | ask | show | jobs
by lispm 4097 days ago
If you look at the literature there are numerous examples of extensible macros. Often this is done for rule-based systems, which also involves matching or unification. Typically one wants to define these rules individually, update them individually, etc.

One needs a registry, an interning function and a driving function. Below is just an example:

    (defvar *patterns* (make-hash-table))
    (defparameter *pattern-names* nil)

    (defun intern-pattern (name if-pattern then-pattern)
      (setf *pattern-names*
            (append *pattern-names* (list name)))
      (setf (gethash name *patterns*)
            (list (compile nil `(lambda (pat)
                                  ,if-pattern))
                  (compile nil `(lambda (pat expr then else)
                                  (declare (ignorable pat expr then else))
                                  ,then-pattern))))
      name)


    (defmacro if-match (pat expr then else)
      (loop for name in *pattern-names*
            for (if-part then-part) = (gethash name *patterns*)
            when (funcall if-part pat)
            do (return (funcall then-part pat expr then else))))

    (intern-pattern 'variable
                    '(and pat (symbolp pat))
                    '`(let ((,pat ,expr)) ,then))
    (intern-pattern 'literal-atom
                    '(atom pat)
                    '`(if (equalp ',pat ,expr) ,then ,else))
    (intern-pattern 'cons
                    '(eq 'cons (car pat))
                    '(destructuring-bind (_ p-car p-cdr) pat
                       (declare (ignore _))
                       (let ((tmp (gensym)))
                         `(let ((,tmp ,expr))
                            (if (consp ,tmp)
                                (if-match ,p-car
                                          (car ,tmp)
                                          (if-match ,p-cdr
                                                    (cdr ,tmp)
                                                    ,then
                                                    ,else)
                                          ,else)
                                ,else)))))
Writing the macro DEFPATTERN is then trivial...

I help maintain an old Lisp-based web server, which was written in the mid-90s on the Symbolics Lisp Machine. It literally has zillions of these registry/intern/machinery/defining-macro combinations...

It's just: one has to program those. But it has been done many many many times.