From: fortunatus
Subject: PRINT and LOAD
Date: 
Message-ID: <7e4b4e94-b936-42f6-ba52-d8da7876120a@k13g2000prh.googlegroups.com>
I like that what you can PRINT you can READ.

I'm trying to PRINT statement expressions that I can LOAD:

(defmacro save-var (var-name file)
 `(print (list 'setq ',var-name ,var-name) ,file))

This example is ok for number, string valued variables.  But falls
down for symbols, lists, which should have ' before the value in the
SETQ.  But it's OK again for arrays since #() is printed...  In all,
it would have to be TYPECASEd to make it universal, which would be
inelegant and frought with oversights if I did it.

Can the printer by itself quote that which requires quoting?

From: Joshua Taylor
Subject: Re: PRINT and LOAD
Date: 
Message-ID: <h3315c$jsk$1@news.eternal-september.org>
fortunatus wrote:
> I like that what you can PRINT you can READ.
> 
> I'm trying to PRINT statement expressions that I can LOAD:
> 
> (defmacro save-var (var-name file)
>  `(print (list 'setq ',var-name ,var-name) ,file))
> 
> This example is ok for number, string valued variables.  But falls
> down for symbols, lists, which should have ' before the value in the
> SETQ.  

Why not print a quote before everything?

CL-USER 4 > (list '1 '"string" '(1 "string" symbol) 'symbol)
(1 "string" (1 "string" SYMBOL) SYMBOL)

//JT
From: fortunatus
Subject: Re: PRINT and LOAD
Date: 
Message-ID: <045cb704-bca4-44e2-b491-68e74d2f56a1@a37g2000prf.googlegroups.com>
On Jul 8, 4:56 pm, Joshua Taylor <······@cs.rpi.edu> wrote:
> Why not print a quote before everything?
>
> CL-USER 4 > (list '1 '"string" '(1 "string" symbol) 'symbol)
> (1 "string" (1 "string" SYMBOL) SYMBOL)
>
> //JT

Gee, too simple for my simple mind to see!  Seems to work fine.
From: TomSW
Subject: Re: PRINT and LOAD
Date: 
Message-ID: <a4b3a39a-4b00-4eb0-9d58-ebb0ce544496@t13g2000yqt.googlegroups.com>
On Jul 8, 10:36 pm, fortunatus <··············@excite.com> wrote:
> I like that what you can PRINT you can READ.
>
> I'm trying to PRINT statement expressions that I can LOAD:
>
> (defmacro save-var (var-name file)
>  `(print (list 'setq ',var-name ,var-name) ,file))
>
> This example is ok for number, string valued variables.  But falls
> down for symbols, lists, which should have ' before the value in the
> SETQ.  But it's OK again for arrays since #() is printed...  In all,
> it would have to be TYPECASEd to make it universal, which would be
> inelegant and frought with oversights if I did it.
>
> Can the printer by itself quote that which requires quoting?

Couldn't you use format with ~S?

eg

(defun write-setf (name value &optional stream)
  (format stream "~S" `(setf ,name ',value)))

(defmacro save-var (var stream)
  `(write-setf ',var ,var ,stream))

---

(let ((v (list 1 2 3 4 5 #(6 7 8 9))))
              (save-var v nil))
=>
"(SETF V '(1 2 3 4 5 #(6 7 8 9)))"

(eval (read-from-string *))
=>
(1 2 3 4 5 #(6 7 8 9))

v
=>
(1 2 3 4 5 #(6 7 8 9))

or maybe I've missed the point...
Tom SW
From: Kaz Kylheku
Subject: Re: PRINT and LOAD
Date: 
Message-ID: <20090721071259.859@gmail.com>
On 2009-07-08, fortunatus <··············@excite.com> wrote:
> I like that what you can PRINT you can READ.
>
> I'm trying to PRINT statement expressions that I can LOAD:
>
> (defmacro save-var (var-name file)
>  `(print (list 'setq ',var-name ,var-name) ,file))

Perversely, I find this confusing without an extra backquote nesting level. :)

Let's see ...

  (defmacro save-var (var-name file)
    `(print `(setq ,',var-name ,,var-name) ,,file))

Ah, now I get it!

In this notation it's obvious you have a triple evaluation of var-name going
on.  The first evaluation reduces the macro argument var-name to the form that
it stands for, namely the symbol.  Then another evaluation wants to treat that
symbol as a Lisp form, reducing it to its value. That value is then placed in
the third position of a SETQ which will treat that value as a form to be
evaluated, and not as that value itself (unless it's a self-evaluating value).

> This example is ok for number, string valued variables.  But falls
> down for symbols, lists, which should have ' before the value in the
> SETQ.

Easily fixed:

  (defmacro save-var (var-name file)
    `(print `(setq ,',var-name ',,var-name) ,,file))
  ;;                           ^  
  ;;                          sproing!

We must put the quote before the commas because it's the last evaluation round,
the one by SETQ, that we want to suppress. The first two evaluations are fine:
we /want/ to reduce VAR-NAME to a symbol, and then reduce that symbol to the
value. 

See, with the double backquote, there is an obvious place to stick the quote.

To work this into the (list ...) we have to start doing ugly crap like this,
where quote appears as a quoted symbol:

  (list 'setq ',var-name (list 'quote ,var-name))

You can't fix the list call just by sticking an apostrophe somewhere; so if
that's what you're looking for, you're going to be pulling an all-nighter.

> But it's OK again for arrays 

It's okay for anything which evaluates to itself. Symbols and (non-empty) lists
do not evaluate to themselves; symbols evaluate to whatever they are bound to,
and lists are compound expressions.

> Can the printer by itself quote that which requires quoting?

No. It would not only have to understand the evaluation semantics of SETQ, but
it would also have to understand your intent that you don't /want/ the second
argument of the SETQ to be evaluated. 
From: Vassil Nikolov
Subject: Re: PRINT and LOAD
Date: 
Message-ID: <snzhbxmcpog.fsf@luna.vassil.nikolov.name>
On Wed, 8 Jul 2009 23:21:50 +0000 (UTC), Kaz Kylheku <········@gmail.com> said:

> On 2009-07-08, fortunatus <··············@excite.com> wrote:
>> I like that what you can PRINT you can READ.
>> 
>> I'm trying to PRINT statement expressions that I can LOAD:
>> 
>> (defmacro save-var (var-name file)
>> `(print (list 'setq ',var-name ,var-name) ,file))

> Perversely, I find this confusing without an extra backquote nesting level. :)

  I suppose because this ought to be a function; this is not a job for
  a macro.

  ---Vassil.


-- 
"Even when the muse is posting on Usenet, Alexander Sergeevich?"
From: Tim Bradshaw
Subject: Re: PRINT and LOAD
Date: 
Message-ID: <2009070908125016807-tfb@cleycom>
On 2009-07-09 07:53:51 +0100, Vassil Nikolov <········@pobox.com> said:

>  I suppose because this ought to be a function; this is not a job for
>   a macro.

It can't easily be a function because of evaluation problems:

(let ((x 1))
  (save-var 'x s))

Can't work.  A version with an extra argument for the value could:

(let ((x 1))
  (save-var 'x x s))

--tim
From: TomSW
Subject: Re: PRINT and LOAD
Date: 
Message-ID: <2152421e-7da4-49c0-bfa6-9d1be90bd504@y19g2000yqy.googlegroups.com>
On Jul 9, 9:12 am, Tim Bradshaw <····@cley.com> wrote:

> It can't easily be a function because of evaluation problems:
>
> (let ((x 1))
>   (save-var 'x s))
>
> Can't work.  A version with an extra argument for the value could:
>
> (let ((x 1))
>   (save-var 'x x s))

On the other hand, if the files that are loaded contain only top-level
setqs, all the variables being set are dynamic and therefore
accessible using symbol-value.
Loading a bunch of setqs might not be the best way to set parameters.

regards,
Tom SW
From: Tim Bradshaw
Subject: Re: PRINT and LOAD
Date: 
Message-ID: <2009070919284616807-tfb@cleycom>
On 2009-07-09 09:15:33 +0100, TomSW <·············@gmail.com> said:

> On the other hand, if the files that are loaded contain only top-level
> setqs, all the variables being set are dynamic and therefore
> accessible using symbol-value.

Good point. 
From: Vassil Nikolov
Subject: Re: PRINT and LOAD
Date: 
Message-ID: <snzbpntc9q1.fsf@luna.vassil.nikolov.name>
On Thu, 9 Jul 2009 08:12:50 +0100, Tim Bradshaw <···@cley.com> said:

> On 2009-07-09 07:53:51 +0100, Vassil Nikolov <········@pobox.com> said:
>> I suppose because this ought to be a function; this is not a job for
>> a macro.

> It can't easily be a function because of evaluation problems:

> (let ((x 1))
>  (save-var 'x s))

> Can't work.  A version with an extra argument for the value could:

> (let ((x 1))
>  (save-var 'x x s))

  My claim is---and perhaps I should have made that more
  explicit---that, to use your example,

    (save-var-the-macro 'x s) -> (save-var-the-function 'x x s)

  is the most there is for a macro to do here (i.e. constructing and
  emitting the resulting form(s) should be done by a function or
  functions).

  (Putting aside the point, already made in the thread, that it is
  unlikely to need this particular feature for lexical variables.  On
  one hand, I am also of the latter opinion, but on the other hand, in
  a "cousin" of this case, lexical variables may well be relevant, so
  it argues both ways, as it were.)

  ---Vassil.


-- 
"Even when the muse is posting on Usenet, Alexander Sergeevich?"
From: fortunatus
Subject: Re: PRINT and LOAD
Date: 
Message-ID: <f1389d23-0325-4392-afff-5f9ec69a5bb7@x25g2000prf.googlegroups.com>
On Jul 8, 7:21 pm, Kaz Kylheku <········@gmail.com> wrote:

> Perversely, I find this confusing without an extra backquote nesting level. :)
> Let's see ...
>   (defmacro save-var (var-name file)
>     `(print `(setq ,',var-name ',,var-name) ,,file))
>   ;;                           ^  
>   ;;                          sproing!

Ah-HA!
From: Vassil Nikolov
Subject: Re: PRINT and LOAD
Date: 
Message-ID: <snzmy7ecpuo.fsf@luna.vassil.nikolov.name>
On Wed, 8 Jul 2009 13:36:44 -0700 (PDT), fortunatus <··············@excite.com> said:

> I like that what you can PRINT you can READ.

  When *PRINT-READABLY* is bound to true.

> I'm trying to PRINT statement expressions that I can LOAD:

> (defmacro save-var (var-name file)
>  `(print (list 'setq ',var-name ,var-name) ,file))

> This example is ok for number, string valued variables.  But falls
> down for symbols, lists, which should have ' before the value in the
> SETQ.  But it's OK again for arrays since #() is printed...  In all,
> it would have to be TYPECASEd to make it universal, which would be
> inelegant and frought with oversights if I did it.

  Maybe not, since Lisp's evaluation rules are fairly simple.  The
  plain vanilla version would be

    (defun value-form-quote-p (value-form)
      "True if the argument needs quoting in a for-evaluation position.
\"Conservative\" version."
      (typep value-form '(or cons symbol)))

  (of course, there is nothing wrong with quoting all value forms;
  avoiding unnecessary quoting is mostly of aesthetic value).

  If the environment in which the form is generated will match the
  environment in which it will later be evaluated (making this
  requirement precise is left as an exercise...), one could do
  something a tad more interesting, e.g.

    (defun value-form-quote-p (value-form)
      "True iff the argument needs quoting in a for-evaluation position.
Assumes that the two environments match.  \"Demo\" grade."
      (cond ((consp value-form) t)
            ((not (symbolp value-form)) nil)
            ((not (constantp value-form)) t)
            ;; some would also like ((keywordp value-form) t) here,
            ;; preferring unquoted keywords only as markers, e.g.
            ;;   (write 'foo :case ':downcase)
            (t (not (eql (symbol-value value-form) value-form)))))

    (mapcar #'(lambda (f) (if (value-form-quote-p f) `',f f))
            '(17 foo :foo "foo" pi t (+ 2 3) #(- 4 5) #C(0 1)))
    => (17 'FOO :FOO "foo" 'PI T '(+ 2 3) #(- 4 5) #C(0 1))

  ---Vassil.


-- 
"Even when the muse is posting on Usenet, Alexander Sergeevich?"
From: fortunatus
Subject: Re: PRINT and LOAD
Date: 
Message-ID: <6a8e6398-5ad1-4635-bfff-ebc31d6c15f7@z4g2000prh.googlegroups.com>
On Jul 9, 2:50 am, Vassil Nikolov <········@pobox.com> wrote:
>   If the environment in which the form is generated will match the
>   environment in which it will later be evaluated...
>     (defun value-form-quote-p (value-form)
>       "True iff the argument needs quoting in a for-evaluation position.
> Assumes that the two environments match.  \"Demo\" grade."
>       (cond ((consp value-form) t)
>             ((not (symbolp value-form)) nil)
>             ((not (constantp value-form)) t)
>             ;; some would also like ((keywordp value-form) t) here,
>             ;; preferring unquoted keywords only as markers, e.g.
>             ;;   (write 'foo :case ':downcase)
>             (t (not (eql (symbol-value value-form) value-form)))))
>   ---Vassil.


Like I said, inelegant and fraught with oversights if I did it...  But
you did it!