From: Mitch Berkson
Subject: Possible to use a template in destructuring-bind?
Date: 
Message-ID: <qTCaj.15612$Fa7.596@newsfe17.lga>
I'd like to read in sexps from a file. Each sexp will follow the same 
template.  Is there a way I can do something like:

(defconstant *template* '(a b c d))

and then

(let ((line-in (read in-str nil nil)))
   (destructuring-bind (?-fn *template*) line-in
      (... manipulate a, b, c, d)))

Is there a ?-fn which will help do this?

Mitch

From: Marco Antoniotti
Subject: Re: Possible to use a template in destructuring-bind?
Date: 
Message-ID: <df9d3a7c-0b24-4a3b-a946-fea56cb1c021@l32g2000hse.googlegroups.com>
On Dec 21, 12:25 am, Mitch Berkson <········@bermita.com> wrote:
> I'd like to read in sexps from a file. Each sexp will follow the same
> template.  Is there a way I can do something like:
>
> (defconstant *template* '(a b c d))
>
> and then
>
> (let ((line-in (read in-str nil nil)))
>    (destructuring-bind (?-fn *template*) line-in
>       (... manipulate a, b, c, d)))
>
> Is there a ?-fn which will help do this?

(Shameless plug) http://common-lisp.net/project/cl-unification/

Cheers

Marco
From: Kaz Kylheku
Subject: Re: Possible to use a template in destructuring-bind?
Date: 
Message-ID: <c91066fe-94f6-4f60-b5ff-9f7a0ef59efe@q77g2000hsh.googlegroups.com>
On Dec 20, 3:25 pm, Mitch Berkson <········@bermita.com> wrote:
> I'd like to read in sexps from a file. Each sexp will follow the same
> template.  Is there a way I can do something like:
>
> (defconstant *template* '(a b c d))
>
> and then
>
> (let ((line-in (read in-str nil nil)))
>    (destructuring-bind (?-fn *template*) line-in
>       (... manipulate a, b, c, d)))
>
> Is there a ?-fn which will help do this?

Others have suggested the read-time evaluation.

You could also write a macro which uses EVAL (only at macro-expansion
time):

(defmacro dstr-bind-template (template object &body forms)
  `(destructuring-bind ,(eval template) ,object ,@forms))

I think I see the problem you're really trying to solve: you have some
data file whose structure is likely to be somewhat of a moving target.
Certain fields will always be there, but perhaps in different
structures. You have more than one instance of a destructuring-bind
and don't want to edit all of them every time the format is revised.

For that case, I would suggest that you create a custom destructuring
macro for that format. Then edit the macro.  The variable names will
still be parameters to the macro, so you don't create the ugly
situation where a block of code refers to magic variables that are not
defined anywhere in sight (having come from the template constant).

(defmacro rip-apart-line ((a-var b-var c-var d-var) line &body forms)
  `(destructuring-bind (,a-var ,b-var ,c-var ,c-var) ,line ,@forms))

So now you have this to maintain instead of the original DEFCONSTANT.
You can change how the four variables are pulled from the structure,
and then just recompile the existing macro calls.

There may be additional advantages. For instance you can use &OPTIONAL
to add new variables in a backward compatible way. Suppose a new field
becomes interesting, let's call it E. You can add support for
extracting E to your macro, but make it an optional element in the
embedded lambda list, like this:

(defmacro rip-apart-line ((a-var b-var c-var d-var
                           &optional (e-var (gensym "E-") e-var-passed-
p))
                          line &body forms)
  `(destructuring-bind (,a-var ,b-var ,c-var ,d-var ,e-var) ,line
      ,@(unless e-var-passed-p `((declare (ignore ,e-var))))
      ,@forms))

So now the destructuring always looks for five elements in the input
line. However, if only four variables are passed to the RIP-APART-LINE
macro, then the fifth variable becomes an internally generated gensym.
It captures the fifth element from the line, and is then unused, which
is taken care of by inserting an IGNORE declaration.

Thus if a field is added, you don't have to fix the existing calls to
the macro in places which are still interested in only the original
four fields.
From: Kent M Pitman
Subject: Re: Possible to use a template in destructuring-bind?
Date: 
Message-ID: <u63yshcsw.fsf@nhplace.com>
Kaz Kylheku <········@gmail.com> writes:

> (defmacro dstr-bind-template (template object &body forms)
>   `(destructuring-bind ,(eval template) ,object ,@forms))

FWIW, I don't like this use of EVAL.  It's the kind of thing
programmers will make errors with.  My personal opinion is that
it's just bad style.
From: Kaz Kylheku
Subject: Re: Possible to use a template in destructuring-bind?
Date: 
Message-ID: <998f71f0-f40c-4c7d-96ff-8352f50ea343@f3g2000hsg.googlegroups.com>
On Dec 20, 8:49 pm, Kent M Pitman <······@nhplace.com> wrote:
> Kaz Kylheku <········@gmail.com> writes:
> > (defmacro dstr-bind-template (template object &body forms)
> >   `(destructuring-bind ,(eval template) ,object ,@forms))
>
> FWIW, I don't like this use of EVAL.  It's the kind of thing
> programmers will make errors with.  My personal opinion is that
> it's just bad style.

Well, if we accept that we are going to be pulling lexical variable
names from a defconstant, we have already accepted bad style as a
given.
From: Kent M Pitman
Subject: Re: Possible to use a template in destructuring-bind?
Date: 
Message-ID: <ubq8khhv1.fsf@nhplace.com>
Mitch Berkson <········@bermita.com> writes:

> I'd like to read in sexps from a file. Each sexp will follow the same
> template.  Is there a way I can do something like:
> 
> (defconstant *template* '(a b c d))
> 
> and then
> 
> (let ((line-in (read in-str nil nil)))
>    (destructuring-bind (?-fn *template*) line-in
>       (... manipulate a, b, c, d)))
> 
> Is there a ?-fn which will help do this?

One way is to do:

 (eval-when (:load-toplevel :compile-toplevel :execute)
   (defvar *template* '(a b c d)))

 (let ((expression-in ;; READ returns an expression, not a "line"
         (read in-str nil nil)))
   (destructuring-bind #.*template* line-in
     ... use a,b,c,d ...))

But the part I don't entirely understand is:  how is it that you know
that a,b,c,d are the vars to use in the body if you don't know the format.
Is it that you're afraid you'll need to rearrange the order or add other
ignored elements?  Otherwise, you don't know if those are the right vars.
From: Mitch
Subject: Re: Possible to use a template in destructuring-bind?
Date: 
Message-ID: <ch9nm3l8ott5v2lc82qutgeucljb2pl5i6@4ax.com>
On 20 Dec 2007 22:00:34 -0500, Kent M Pitman <······@nhplace.com>
wrote:

> (let ((expression-in ;; READ returns an expression, not a "line"
>         (read in-str nil nil)))
>   (destructuring-bind #.*template* line-in
>     ... use a,b,c,d ...))
>
>But the part I don't entirely understand is:  how is it that you know
>that a,b,c,d are the vars to use in the body if you don't know the format.
>Is it that you're afraid you'll need to rearrange the order or add other
>ignored elements?  Otherwise, you don't know if those are the right vars.

Yes. That wasn't completely clear to me when I asked about this. I can
specify the variables in the template, but then when the template is
used later, the variables will have to magically appear in the body of
the function.

So, even though there are several good solutions here, especially if
the destructuring were occuring in more than one place, it might be
better for me to have the template explicitly in the d-b (since I am
only doing it one place).

Mitch
From: Maciej Katafiasz
Subject: Re: Possible to use a template in destructuring-bind?
Date: 
Message-ID: <fkf1bv$8bv$2@news.net.uni-c.dk>
Den Thu, 20 Dec 2007 18:25:15 -0500 skrev Mitch Berkson:

> I'd like to read in sexps from a file. Each sexp will follow the same
> template.  Is there a way I can do something like:
> 
> (defconstant *template* '(a b c d))
> 
> and then
> 
> (let ((line-in (read in-str nil nil)))
>    (destructuring-bind (?-fn *template*) line-in
>       (... manipulate a, b, c, d)))
> 
> Is there a ?-fn which will help do this?

Yes, the reader macro #. should help you. So that it becomes:
(destructuring-bind (#.*template*) line-in ...

Cheers,
Maciej