From: Lei
Subject: A macro question
Date: 
Message-ID: <esqc06$dmb$1@news.asu.edu>
Hi, folks.

I want to implement some utility: save some global variables to 
different files according to the name. Suppose you have a global 
variable *foo*, then it will be saved in a file named as "foo".

I don't know how to implement this by just a function, thus, I defined a 
  macro like below:

(defmacro save-var (var)
   "Save a variable in the foler var with its symbol name."
   `(let ((fname (string-trim "*" (string ',var))))
     (print fname)
     (save-var-to-file ,var fname)))

(defun save-var-to-file (var fname)
   "Save the variable to a file."
   (with-open-file (f fname :direction :output
		     :if-exists :supersede
		     :if-does-not-exist :create)
     (print var f)))

Is this a correct way to go? (Probably there are better ways)

I have around 50 global variables (*foo*, *bar*, ...)

Of course, I can define a function like
(defun save-all ()
    (save-var *foo*)
    (save-var *bar*)
     ....
)

OK, but isn't it just too bothersome as I have to write (save-var ...) 
for each variable.  So, I change it a little bit:

(defun save-all ()
     (mapc #'(lambda (x)
               (save-var x))
             '(*foo*  *bar*  ...)))

Unfortunately, all the variables are saved in the same file named as 
"X".  So, my limited knowledge of lisp suggest: it might be better to 
use a macro. And the following is my last attempt:

(defmacro save-all ()
    (mapc #'(lambda (x)
               `(save-var ,x))
             '(*foo*  *bar*  ...)))

Then, this macro generate some code like below:
((save-var *foo*) (save-var *bar*) ...)

When I evaluate it, as you might expect, it signals an error.
Actually, what I really want is to generate code like:
(save-var *foo*) (save-var *bar*) ...

How to resolve this problem?

I know this post is way too long. Thanks a lot for your patience.
Maybe, I make this simple problem too complicated. Any suggestion is 
highly appreciated!!

-Lei

From: Kaz Kylheku
Subject: Re: A macro question
Date: 
Message-ID: <1173405587.380501.88110@t69g2000cwt.googlegroups.com>
On Mar 8, 5:09 pm, Lei <······@asu.edu> wrote:
> Hi, folks.
>
> I want to implement some utility: save some global variables to
> different files according to the name. Suppose you have a global
> variable *foo*, then it will be saved in a file named as "foo".
>
> I don't know how to implement this by just a function, thus, I defined a
>   macro like below:
>
> (defmacro save-var (var)
>    "Save a variable in the foler var with its symbol name."
>    `(let ((fname (string-trim "*" (string ',var))))

Why do the string conversion and trimming at run time? It could be
done at macro-expansion time.

  (let ((fname (string-trim "*" (string var))))
    `(save-var-to-file ,var ,fname))

That's the whole point, to make the macro write the string literal for
you based on the name of the variable, so you don't have to type it.

>      (print fname)
>      (save-var-to-file ,var fname)))

> (defun save-var-to-file (var fname)
>    "Save the variable to a file."
>    (with-open-file (f fname :direction :output
>                      :if-exists :supersede
>                      :if-does-not-exist :create)
>      (print var f)))

This function is more general than its name implies. It saves the
printed representation of an argument value to a file. It could just
be called SAVE-TO-FILE.

You could just call this function directly and avoid the macro
wrapper, which doesn't do much.

 (save-to-file *foo* "foo")

This is actually more readable code. It's not worth it to make a macro
do this.

> (defmacro save-all ()
>     (mapc #'(lambda (x)
>                `(save-var ,x))
>              '(*foo*  *bar*  ...)))
>
> Then, this macro generate some code like below:
> ((save-var *foo*) (save-var *bar*) ...)


Close. A list of compound forms isn't a program. To make it into one,
you  need the PROGN operator:

  (progn (save-var *foo*) (save-var *bar*) ...)


> When I evaluate it, as you might expect, it signals an error.
> Actually, what I really want is to generate code like:
> (save-var *foo*) (save-var *bar*) ...

That is impossible. A macro can only generate one form. You might
think that  multiple values returned from a macro could do this, but
it doesn't work that way; only the first value is taken.

PROGN solves this problem. If a PROGN appears in a top level, its
constituent forms are still top-level forms. Thus a PROGN can wrap
things like DEFUN, DEFCLASS, DEFVAR, etc.
From: Lei
Subject: Re: A macro question
Date: 
Message-ID: <esqtol$3tf$2@news.asu.edu>
Kaz Kylheku wrote:
> On Mar 8, 5:09 pm, Lei <······@asu.edu> wrote:
>> Hi, folks.
>>
>> I want to implement some utility: save some global variables to
>> different files according to the name. Suppose you have a global
>> variable *foo*, then it will be saved in a file named as "foo".
>>
>> I don't know how to implement this by just a function, thus, I defined a
>>   macro like below:
>>
>> (defmacro save-var (var)
>>    "Save a variable in the foler var with its symbol name."
>>    `(let ((fname (string-trim "*" (string ',var))))
> 
> Why do the string conversion and trimming at run time? It could be
> done at macro-expansion time.
> 
>   (let ((fname (string-trim "*" (string var))))
>     `(save-var-to-file ,var ,fname))
> 
> That's the whole point, to make the macro write the string literal for
> you based on the name of the variable, so you don't have to type it.
> 
>>      (print fname)
>>      (save-var-to-file ,var fname)))
> 
>> (defun save-var-to-file (var fname)
>>    "Save the variable to a file."
>>    (with-open-file (f fname :direction :output
>>                      :if-exists :supersede
>>                      :if-does-not-exist :create)
>>      (print var f)))
> 
> This function is more general than its name implies. It saves the
> printed representation of an argument value to a file. It could just
> be called SAVE-TO-FILE.
> 
> You could just call this function directly and avoid the macro
> wrapper, which doesn't do much.
> 
>  (save-to-file *foo* "foo")
> 
> This is actually more readable code. It's not worth it to make a macro
> do this.
> 
>> (defmacro save-all ()
>>     (mapc #'(lambda (x)
>>                `(save-var ,x))
>>              '(*foo*  *bar*  ...)))
>>
>> Then, this macro generate some code like below:
>> ((save-var *foo*) (save-var *bar*) ...)
> 
> 
> Close. A list of compound forms isn't a program. To make it into one,
> you  need the PROGN operator:
> 
>   (progn (save-var *foo*) (save-var *bar*) ...)
> 
> 
>> When I evaluate it, as you might expect, it signals an error.
>> Actually, what I really want is to generate code like:
>> (save-var *foo*) (save-var *bar*) ...
> 
> That is impossible. A macro can only generate one form. You might
> think that  multiple values returned from a macro could do this, but
> it doesn't work that way; only the first value is taken.
> 
> PROGN solves this problem. If a PROGN appears in a top level, its
> constituent forms are still top-level forms. Thus a PROGN can wrap
> things like DEFUN, DEFCLASS, DEFVAR, etc.
> 
Nice. I'll try to wrap up with progn next time.
I decided to write only functions this time.

Writing macros seems unnecessary for this task.

Anyway, thanks!!
From: dpapathanasiou
Subject: Re: A macro question
Date: 
Message-ID: <1173453159.476605.234400@p10g2000cwp.googlegroups.com>
> Writing macros seems unnecessary for this task.

Here's something which might be of interest to you, since it addresses
the question of why to use macros in a file I/O example:
http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html
From: Alexander Schmolck
Subject: Re: A macro question
Date: 
Message-ID: <yfsps7ibfmi.fsf@oc.ex.ac.uk>
"dpapathanasiou" <···················@gmail.com> writes:

> > Writing macros seems unnecessary for this task.
> 
> Here's something which might be of interest to you, since it addresses
> the question of why to use macros in a file I/O example:
> http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html

Writing macros seems unnecssary for these tasks[1] ;)

'as

Footnotes: 
[1]  I.e. if you find yourself writing while/do-* loop or with-* macros, that's
     presumably saying something bad about your language rather than something
     good about macros.
From: Edi Weitz
Subject: Re: A macro question
Date: 
Message-ID: <uk5xqzalu.fsf@agharta.de>
On 09 Mar 2007 15:28:37 +0000, Alexander Schmolck <··········@gmail.com> wrote:

> if you find yourself writing while/do-* loop or with-* macros,
> that's presumably saying something bad about your language rather
> than something good about macros.

Nonsense.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Ken Tilton
Subject: Re: A macro question
Date: 
Message-ID: <_kiIh.19$6J.15@newsfe12.lga>
Edi Weitz wrote:
> On 09 Mar 2007 15:28:37 +0000, Alexander Schmolck <··········@gmail.com> wrote:
> 
> 
>>if you find yourself writing while/do-* loop or with-* macros,
>>that's presumably saying something bad about your language rather
>>than something good about macros.
> 
> 
> Nonsense.
> 

Nonsense? I was going to say "troll". But a welcome one, been quiet 
around here, the hounds are getting listless, some live bait would 
really pick up their spirits.

kt

-- 

"As long as algebra is taught in school,
there will be prayer in school." - Cokie Roberts

"Stand firm in your refusal to remain conscious during algebra."
    - Fran Lebowitz

"I'm an algebra liar. I figure two good lies make a positive."
    - Tim Allen

"Algebra is the metaphysics of arithmetic." - John Ray

http://www.theoryyalgebra.com/
From: Alexander Schmolck
Subject: Re: A macro question
Date: 
Message-ID: <yfslki6bavj.fsf@oc.ex.ac.uk>
Edi Weitz <········@agharta.de> writes:

> On 09 Mar 2007 15:28:37 +0000, Alexander Schmolck <··········@gmail.com> wrote:
> 
> > if you find yourself writing while/do-* loop or with-* macros,
> > that's presumably saying something bad about your language rather
> > than something good about macros.
> 
> Nonsense.

If you find yourself repeatedly implementing while/do-* loops chances are your
language misses basic constructs like proper iteration abstractions and
although I wouldn't claim that with-* macros are equally indicative of
fundamental weaknesses I'm also not convinced that this type of resource
allocation/deallocation pattern can't be handled better than handcoding a
macro for each such ressource (which of course still handily beats handcoding
some try/finally boilerplate for each such ressource *usage*).

So, I don't actually think these examples are such a convincing answer to the
question "What is the point of lisp-style macros?", unless you take the answer
to be "to duct-tape over language deficiencies" (maybe upon reflection a
pretty plausible answer but presumably not the one most people in c.l.l. would
give).

'as
From: Ari Johnson
Subject: Re: A macro question
Date: 
Message-ID: <m2irdanwhg.fsf@hermes.theari.com>
Alexander Schmolck <··········@gmail.com> writes:

> Edi Weitz <········@agharta.de> writes:
>
>> On 09 Mar 2007 15:28:37 +0000, Alexander Schmolck <··········@gmail.com> wrote:
>> 
>> > if you find yourself writing while/do-* loop or with-* macros,
>> > that's presumably saying something bad about your language rather
>> > than something good about macros.
>> 
>> Nonsense.
>
> If you find yourself repeatedly implementing while/do-* loops chances are your
> language misses basic constructs like proper iteration abstractions and
> although I wouldn't claim that with-* macros are equally indicative of
> fundamental weaknesses I'm also not convinced that this type of resource
> allocation/deallocation pattern can't be handled better than handcoding a
> macro for each such ressource (which of course still handily beats handcoding
> some try/finally boilerplate for each such ressource *usage*).
>
> So, I don't actually think these examples are such a convincing answer to the
> question "What is the point of lisp-style macros?", unless you take the answer
> to be "to duct-tape over language deficiencies" (maybe upon reflection a
> pretty plausible answer but presumably not the one most people in c.l.l. would
> give).

Notwithstanding that nobody repeatedly implements while/do-* loops in
Common Lisp, because they just use LOOP or ITERATE, notwithstanding
that the with-* practice makes sense and helps channel every instance
of any given bug into one easy-to-find and -fix place, and
notwithstanding that you don't offer any better solution to what you
classify as simply a resource allocation/deallocation pattern, I'll
bite.

If you define "language deficiencies" as anything that the language at
hand doesn't do out of the box, then you have offered a fair and
indeed flattering answer to the question posed.  Every language will
have deficiencies in a large subset of all problem domains.[1]  Macros
let you get around those deficiencies by bringing Lisp closer to being
the perfect language for solving a given problem.[2]  The point isn't
that Lisp is the perfect language for every problem, standing on its
own.  It's rather that macros allow Lisp to be formed into the perfect
language for a given problem.

If Lisp macros are duct tape to cover up language deficiencies, then
feel free to list languages that either lack every deficiency of Lisp
without introducing deficiencies that it lacks or provide as useful a
form of duct tape.


[1] If you know of one that has no such deficiencies, please do let me
    know about it.)
[2] This applies whether the problem is accessing mutex-controlled
    resources with no bug-prone separate boilerplate at every turn,
    solving logical dependencies a la Prolog, seamlessly accessing
    database resources within your program, or anything else that
    your language doesn't already do well.
From: Alan Crowe
Subject: Re: A macro question
Date: 
Message-ID: <86k5xqkzfp.fsf@cawtech.freeserve.co.uk>
Alexander Schmolck <··········@gmail.com> writes:

> although I wouldn't claim that with-* macros are equally indicative of
> fundamental weaknesses I'm also not convinced that this type of resource
> allocation/deallocation pattern can't be handled better than handcoding a
> macro for each such ressource (which of course still handily beats handcoding
> some try/finally boilerplate for each such ressource *usage*).

No need to handcode them. 

CL-USER> (defmacro define-release-macro (name releaser)
           `(defmacro ,name ((var init) &body code)
             `(let ((,var ,init))
               (unwind-protect
                    (progn ,@code)
                 (,',releaser ,var)))))
DEFINE-RELEASE-MACRO

CL-USER> (macroexpand-1 '(define-release-macro with-care let-go))
(DEFMACRO WITH-CARE ((VAR INIT) &BODY CODE)
  `(LET ((,VAR ,INIT))
     (UNWIND-PROTECT (PROGN ,@CODE) (LET-GO ,VAR))))
T

CL-USER> (define-release-macro with-care let-go)
WITH-CARE

CL-USER> (macroexpand-1 '(with-care (n (grab "n"))
                           (stamp n)
                           (pickle n)))
(LET ((N (GRAB "n")))
  (UNWIND-PROTECT (PROGN (STAMP N) (PICKLE N)) (LET-GO N)))

Alan Crowe
Edinburgh
Scotland
From: Vassil Nikolov
Subject: Re: A macro question
Date: 
Message-ID: <yy8vy7m4fv9i.fsf@eskimo.com>
On 09 Mar 2007 17:11:12 +0000, Alexander Schmolck <··········@gmail.com> said:
| ...
| with-* macros [referred to as a] type of resource allocation/deallocation
| pattern

  As an aside, with- macros are for establishing dynamic extents, which
  includes (many cases of) resource allocation/deallocation, but is not
  limited to that (see e.g. WITH-STANDARD-IO-SYNTAX, which is not about
  resource management).

  ---Vassil.


-- 
Is your code free of side defects?
From: ············@gmail.com
Subject: Re: A macro question
Date: 
Message-ID: <1173652241.190612.319290@30g2000cwc.googlegroups.com>
On Mar 9, 8:28 am, Alexander Schmolck <··········@gmail.com> wrote:
> [1]  I.e. if you find yourself writing while/do-* loop or with-* macros, that's
>      presumably saying something bad about your language rather than something
>      good about macros.

Well, for me the with-* macros are more about self-documenting code
than about macro convenience.  You could imagine forcing every
resource to have the same interface:

(defmethod reserve ((resource <type>) &rest args) ...)
(defmethod release ((resource <type>)) ...)

(defmacro with-resource (resource &key (args nil) &body body) ...)

The problem is, not every resource requires the same number or kind of
arguments.  The unified interface prevents you from using syntax to
enforce things like number of arguments, type of arguments, etc.  More
importantly, WITH-RESOURCE isn't that descriptive of a name.

Another approach is to use Python-style iterators, but those are
designed for _iteration_ (over a loop) and not for the specific case
of resource allocation.  (For example, when using WITH-OPEN-FILE, you
may only want to read the first line of the file.)  Furthermore this
reduces to the problem of the previous paragraph.

mfh
From: Sacha
Subject: Re: A macro question
Date: 
Message-ID: <t43Ih.51810$7m.429176@phobos.telenet-ops.be>
> Then, this macro generate some code like below:
> ((save-var *foo*) (save-var *bar*) ...)
> 
> When I evaluate it, as you might expect, it signals an error.
> Actually, what I really want is to generate code like:
> (save-var *foo*) (save-var *bar*) ...
> 
> How to resolve this problem?
> 

You might want to generate

(progn
   (save-var *foo*)
   (save-var *bar*))

Sacha
From: Rainer Joswig
Subject: Re: A macro question
Date: 
Message-ID: <joswig-274596.02471709032007@news-europe.giganews.com>
In article <············@news.asu.edu>, Lei <······@asu.edu> wrote:

> Hi, folks.
> 
> I want to implement some utility: save some global variables to 
> different files according to the name. Suppose you have a global 
> variable *foo*, then it will be saved in a file named as "foo".
> 
> I don't know how to implement this by just a function, thus, I defined a 
>   macro like below:
> 
> (defmacro save-var (var)
>    "Save a variable in the foler var with its symbol name."
>    `(let ((fname (string-trim "*" (string ',var))))
>      (print fname)
>      (save-var-to-file ,var fname)))

Why do you need a macro?

(save-var *foo*) vs. (save-var '*foo*)  ?

With a function you have to write the latter. But
that is a small price to pay.

As a basic rule: don't write macros. Write functions.
If you think you need a macro, think again.

Functions are easier to understand, easier to debug,
easier to write, easier to maintain, ...


> (defun save-var-to-file (var fname)
>    "Save the variable to a file."
>    (with-open-file (f fname :direction :output
> 		     :if-exists :supersede
> 		     :if-does-not-exist :create)
>      (print var f)))
> 
> Is this a correct way to go? (Probably there are better ways)
> 
> I have around 50 global variables (*foo*, *bar*, ...)
> 
> Of course, I can define a function like
> (defun save-all ()
>     (save-var *foo*)
>     (save-var *bar*)
>      ....
> )
> 
> OK, but isn't it just too bothersome as I have to write (save-var ...) 
> for each variable.  So, I change it a little bit:
> 
> (defun save-all ()
>      (mapc #'(lambda (x)
>                (save-var x))
>              '(*foo*  *bar*  ...)))

With a function SAVE-VAR it would work.
Note that you then also can write:

(defun save-all ()
     (mapc #'save-var '(*foo*  *bar*  ...)))



> 
> Unfortunately, all the variables are saved in the same file named as 
> "X".  So, my limited knowledge of lisp suggest: it might be better to 
> use a macro. And the following is my last attempt:
> 
> (defmacro save-all ()
>     (mapc #'(lambda (x)
>                `(save-var ,x))
>              '(*foo*  *bar*  ...)))

No. 

> 
> Then, this macro generate some code like below:
> ((save-var *foo*) (save-var *bar*) ...)
> 
> When I evaluate it, as you might expect, it signals an error.
> Actually, what I really want is to generate code like:
> (save-var *foo*) (save-var *bar*) ...
> 
> How to resolve this problem?

Write a function SAVE-VAR and map over the symbols.


> 
> I know this post is way too long. Thanks a lot for your patience.
> Maybe, I make this simple problem too complicated. Any suggestion is 
> highly appreciated!!
> 
> -Lei

-- 
http://lispm.dyndns.org
From: Lei
Subject: Re: A macro question
Date: 
Message-ID: <esqtkc$3tf$1@news.asu.edu>
Rainer Joswig wrote:
> In article <············@news.asu.edu>, Lei <······@asu.edu> wrote:
> 
>> Hi, folks.
>>
>> I want to implement some utility: save some global variables to 
>> different files according to the name. Suppose you have a global 
>> variable *foo*, then it will be saved in a file named as "foo".
>>
>> I don't know how to implement this by just a function, thus, I defined a 
>>   macro like below:
>>
>> (defmacro save-var (var)
>>    "Save a variable in the foler var with its symbol name."
>>    `(let ((fname (string-trim "*" (string ',var))))
>>      (print fname)
>>      (save-var-to-file ,var fname)))
> 
> Why do you need a macro?
> 
> (save-var *foo*) vs. (save-var '*foo*)  ?
> 
> With a function you have to write the latter. But
> that is a small price to pay.
> 
> As a basic rule: don't write macros. Write functions.
> If you think you need a macro, think again.
> 
> Functions are easier to understand, easier to debug,
> easier to write, easier to maintain, ...

Thanks! I changed to (save-var '*foo*), and use only functions. It works 
perfect now.  I didn't fully understand the meaning of symbol in lisp yet :(

> 
> 
>> (defun save-var-to-file (var fname)
>>    "Save the variable to a file."
>>    (with-open-file (f fname :direction :output
>> 		     :if-exists :supersede
>> 		     :if-does-not-exist :create)
>>      (print var f)))
>>
>> Is this a correct way to go? (Probably there are better ways)
>>
>> I have around 50 global variables (*foo*, *bar*, ...)
>>
>> Of course, I can define a function like
>> (defun save-all ()
>>     (save-var *foo*)
>>     (save-var *bar*)
>>      ....
>> )
>>
>> OK, but isn't it just too bothersome as I have to write (save-var ...) 
>> for each variable.  So, I change it a little bit:
>>
>> (defun save-all ()
>>      (mapc #'(lambda (x)
>>                (save-var x))
>>              '(*foo*  *bar*  ...)))
> 
> With a function SAVE-VAR it would work.
> Note that you then also can write:
> 
> (defun save-all ()
>      (mapc #'save-var '(*foo*  *bar*  ...)))
> 
> 
> 
>> Unfortunately, all the variables are saved in the same file named as 
>> "X".  So, my limited knowledge of lisp suggest: it might be better to 
>> use a macro. And the following is my last attempt:
>>
>> (defmacro save-all ()
>>     (mapc #'(lambda (x)
>>                `(save-var ,x))
>>              '(*foo*  *bar*  ...)))
> 
> No. 
> 
>> Then, this macro generate some code like below:
>> ((save-var *foo*) (save-var *bar*) ...)
>>
>> When I evaluate it, as you might expect, it signals an error.
>> Actually, what I really want is to generate code like:
>> (save-var *foo*) (save-var *bar*) ...
>>
>> How to resolve this problem?
> 
> Write a function SAVE-VAR and map over the symbols.
> 
> 
>> I know this post is way too long. Thanks a lot for your patience.
>> Maybe, I make this simple problem too complicated. Any suggestion is 
>> highly appreciated!!
>>
>> -Lei
>