[pro] The Best Examples of "Code is Data"

Ram Krishnan kriyative at gmail.com
Mon Sep 6 17:18:18 UTC 2010


On Sun, Sep 5, 2010 at 5:24 AM, Kazimir Majorinc <kazimir at chem.pmf.hr> wrote:
> As first, good luck with this list!
>
> I'm in search for best examples of "code is data" paradigm in Common
> Lisp. For most CL-ers, it probably means "macros", but eval, backquote,
> anything that processes the code as data is of interest. As "best" I
> think on the most surprising, powerful, sophisticated examples, not
> necessarily of a pedagogical value.
>
> Imagine that someone invited you to write the presentation "Five best CL
> macros ... I seen" or "Five best CL macros ... I wrote." What would you
> chose and why?

Look forward to seeing more great macros from others on the list.

Here's a macro I wrote called `bind' that I got a lot of utility from
in a recent project. It was inspired by the `metabang-bind' facility
(http://common-lisp.net/project/metabang-bind/), but with simpler and
slightly different goals.

>From the docstring:

  This macro combines the behaviour of the forms `let*',
  `destructuring-bind', and `multiple-value-bind', permitting the
  following style of binding form:

  (bind (((:values m n) (values 10 20))
         ((a b _c &key (d 10)) '(1 2 3))
         (x 5))
    (+ x a b d m n))
  => 48

While Lisp purists may dislike it, I picked up the _foo notation for
ignorable vars from Erlang, which can be handy at times.

----------------

(defmacro bind (clauses &body body)
  "This macro combines the behaviour of the forms `let*',
`destructuring-bind', and `multiple-value-bind', permitting the
following style of binding form:

  (bind (((:values m n) (values 10 20))
         ((a b _c &key (d 10)) '(1 2 3))
         (x 5))
    (+ x a b d m n))
  => 48

Note in the destructuring form (a b _c &key (d 10)), _c is a short form
for declaring it as ignorable.

This is a more limited and lightweight implementation of some ideas from
metabang-bind (http://common-lisp.net/project/metabang-bind/)."
  (labels
      ((parse-arglist (args)
         (loop
            for arg in args
            collect arg into args
            when (and (symbolp arg) (eq (aref (symbol-name arg) 0) #\_))
            collect arg into ignorables
            finally (return (values args ignorables))))
       (cons-form (form args clauses body)
         (multiple-value-bind (arglist ignorables)
             (parse-arglist args)
           `(,form ,arglist
                   ,@(cdar clauses)
                   ,@(when ignorables `((declare ,(list* 'ignore ignorables))))
                   (bind ,(cdr clauses) , at body)))))
    (cond
      ((null clauses) `(progn , at body))
      ((listp (caar clauses))
       (cond
         ((eq (caaar clauses) :values)
          (cons-form 'multiple-value-bind (cdaar clauses) clauses body))
         ((eq (caaar clauses) :slots)
          `(with-slots ,(cdaar clauses) ,@(cdar clauses)
             (bind ,(cdr clauses) , at body)))
         (t
          (cons-form 'destructuring-bind (caar clauses) clauses body))))
      (t
       `(let (,(car clauses))
          (bind ,(cdr clauses) , at body))))))

----------------

Cheers,

-ram




More information about the pro mailing list