From: Friedrich Dominicus
Subject: Macros vs Functions and a question about check-type
Date: 
Message-ID: <877lb94t5w.fsf@q-software-solutions.com>
I'm trying getting a bit more familiar with Common Lisp and write some
small piecs of code. I come along with this ones:
(defun with-cwd (dir thunk)
  (let ((old-wd (pwd)))
    (unwind-protect
        (progn
          (change-directory dir)
          (funcall thunk))
      (change-directory old-wd))))

(defmacro with-cwd-m (dir thunk)
  (let ((old-wd (gensym)))
    `(let ((,old-wd (pwd)))
       (declare (dynamic-extent ,old-wd))
       (unwind-protect
           (progn
             (change-directory ,dir)
             (funcall ,thunk))
         (change-directory ,old-wd)))))

comments are ommitted frankly here.

Now my questions:
- all the other with-... functions I found in Common Lisp are macros,
so I think this one might be better written as a macro. Can someone
explain, why the macro may be the better-choice.

- I found the line with (declare (dynamic-exte... in On Lisp page 149,
it seems to me that using it might be ok here too. But I'm not sure,
can someone explain why it might be good or if I better should omitt
it.




Now a somewhat related question but a bit away. I want the 
first parameter of the funtion/macro be a String and the second to be
a function with no parameter.

I can put in a (check-type dir string) and this will go through but I
can not find out how to state that thunk should be a function with no
parameter.

I found this in the Hyperspec:
The list form of the function type-specifier can be used only for
declaration and not for discrimination. 

The latter suggests that I may out of luck, but I do not know if I
understand it correctly.

Thanks for taking the time
Friedrich
-- 
for e-mail reply remove all after .com 

From: Barry Margolin
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <7tr65.97$MK2.2086@burlma1-snr2>
In article <··············@q-software-solutions.com>,
Friedrich Dominicus  <·····@q-software-solutions.com.NO-spam> wrote:
>I'm trying getting a bit more familiar with Common Lisp and write some
>small piecs of code. I come along with this ones:
>(defun with-cwd (dir thunk)
>  (let ((old-wd (pwd)))
>    (unwind-protect
>        (progn
>          (change-directory dir)
>          (funcall thunk))
>      (change-directory old-wd))))
>
>(defmacro with-cwd-m (dir thunk)
>  (let ((old-wd (gensym)))
>    `(let ((,old-wd (pwd)))
>       (declare (dynamic-extent ,old-wd))
>       (unwind-protect
>           (progn
>             (change-directory ,dir)
>             (funcall ,thunk))
>         (change-directory ,old-wd)))))
>
>comments are ommitted frankly here.
>
>Now my questions:
>- all the other with-... functions I found in Common Lisp are macros,
>so I think this one might be better written as a macro. Can someone
>explain, why the macro may be the better-choice.

Typically, the macro wouldn't take a thunk, but use &body so that the user
doesn't have to write (lambda ...).  It makes you macro look like most
other Lisp constructs.  You can use the function in the implementation of
the macro, though:

(defmacro with-cwd-m (dir &body body)
  `(with-cwd ,dir (lambda () ,@body)))

This is hygienic without needing the gensym.

Typically, WITH-CWD would be the name of the macro that you advertise to
users, and the function might be named something like WITH-CWD-INTERNAL.

>- I found the line with (declare (dynamic-exte... in On Lisp page 149,
>it seems to me that using it might be ok here too. But I'm not sure,
>can someone explain why it might be good or if I better should omitt
>it.

It's not likely to make much difference, especially in a modern Lisp with
generational GC.  It also isn't necessarily correct, since you don't know
that CHANGE-DIRECTORY isn't saving the value somewhere.

Where it's useful is generally with larger data structures, since GC's
occur more frequently if you allocate more data on the heap.

>Now a somewhat related question but a bit away. I want the 
>first parameter of the funtion/macro be a String and the second to be
>a function with no parameter.
>
>I can put in a (check-type dir string) and this will go through but I
>can not find out how to state that thunk should be a function with no
>parameter.
>
>I found this in the Hyperspec:
>The list form of the function type-specifier can be used only for
>declaration and not for discrimination. 
>
>The latter suggests that I may out of luck, but I do not know if I
>understand it correctly.

You're correct.  Implementations aren't required to remember the number of
arguments that a function takes, which they would have to do if the
complete signature of the function could be checked with TYPEP.

If you have everything compiled with high safety, the system will signal an
error if you call the function with the wrong number of arguments.  If you
want to customize how this is reported to the user, you can establish a
handler for the condition.

Note that if you only export the macro I defined above, it can't produce a
thunk that expects the wrong number of arguments.  If a user calls
non-exported functions they have no right to expect them to behave nicely.

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Phil Stubblefield
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <395A4992.FBF77D1E@rpal.rockwell.com>
Just a few additions to barmar's commentary:

Barry Margolin <······@genuity.net> wrote:
> 
> In article <··············@q-software-solutions.com>,
> Friedrich Dominicus  <·····@q-software-solutions.com.NO-spam> wrote:
> > 
> > [...]
> > 
> > Now my questions:
> > - all the other with-... functions I found in Common Lisp are
> > macros, so I think this one might be better written as a
> > macro. Can someone explain, why the macro may be the
> > better-choice.
> 
> Typically, the macro wouldn't take a thunk, but use &body so that
> the user doesn't have to write (lambda ...).  It makes you macro
> look like most other Lisp constructs.  You can use the function in
> the implementation of the macro, though:
> 
> (defmacro with-cwd-m (dir &body body)
>   `(with-cwd ,dir (lambda () ,@body)))
> 
> This is hygienic without needing the gensym.
> 
> Typically, WITH-CWD would be the name of the macro that you
> advertise to users, and the function might be named something like
> WITH-CWD-INTERNAL.

Two other common idioms for naming the functional version would be
CALL-WITH-CWD and INVOKE-WITH-CWD, especially if you advertise the
functional interface by exporting its name from your package.

When defining a macro of the form WITH-xxx, I also tend to make the
first argument a list (sometimes even an empty list) so that I can
add optional or keyword arguments later without having to change
existing source code.

I probably would have written your examples as follows (also
omitting doc strings):

(defmacro with-cwd ((directory) &body body)
  `(call-with-cwd ,directory #'(lambda () ,@body)))

(defun call-with-cwd (directory thunk)
  (let ((old-wd (pwd)))
    (unwind-protect
        (progn
          (change-directory directory)
          (funcall thunk))
      (change-directory old-wd))))

Your tastes may vary.


Phil Stubblefield
Rockwell Palo Alto Laboratory                               206/655-3204
http://www.rpal.rockwell.com/~phil                ····@rpal.rockwell.com
From: Friedrich Dominicus
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <8766qt6kld.fsf@q-software-solutions.com>
> 
> I probably would have written your examples as follows (also
> omitting doc strings):
> 
> (defmacro with-cwd ((directory) &body body)
>   `(call-with-cwd ,directory #'(lambda () ,@body)))
> 
> (defun call-with-cwd (directory thunk)
>   (let ((old-wd (pwd)))
>     (unwind-protect
>         (progn
>           (change-directory directory)
>           (funcall thunk))
>       (change-directory old-wd))))

It is not clear to me why I should use both. I was thinking either a
macro or a functon would be enough. In ON Lisp I found often the
combination from macro and function, but I can't figure out why in
this I guess simple case one should divide it into a macro and
function part. 

Another point which was not stated clearly is what seems to be the
"better" approach. Writing it down as a function or a macro

With best regards
Friedrich

-- 
for e-mail reply remove all after .com 
From: Phil Stubblefield
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <395B80C6.A132A750@rpal.rockwell.com>
Friedrich Dominicus <·····@q-software-solutions.com> wrote:
> 
> > I probably would have written your examples as follows (also
> > omitting doc strings):
> >
> > (defmacro with-cwd ((directory) &body body)
> >   `(call-with-cwd ,directory #'(lambda () ,@body)))
> >
> > (defun call-with-cwd (directory thunk)
> >   (let ((old-wd (pwd)))
> >     (unwind-protect
> >         (progn
> >           (change-directory directory)
> >           (funcall thunk))
> >       (change-directory old-wd))))
> 
> It is not clear to me why I should use both. I was thinking either
> a macro or a functon would be enough. In ON Lisp I found often the
> combination from macro and function, but I can't figure out why in
> this I guess simple case one should divide it into a macro and
> function part.
> 
> Another point which was not stated clearly is what seems to be the
> "better" approach. Writing it down as a function or a macro

I'll be duplicating much of what Paul Foley already wrote, but
here are my own answers.

1. Should I use a macro or a function?

   Generally, you should use a macro whenever your definition does
   not use the normal, functional rules of evaluation.  Using your
   example, suppose you want to be able to write code like this:

     (with-cwd ("/foo/quux")
       (do-something))

   For one thing, "/foo/quux" is not a valid function, and so an
   error would be signaled.  Of course, your original syntax didn't
   have that set of parentheses; I added them in order to facilitate
   any later revisions.  For the sake of argument, let's return to
   your original syntax:

     (with-cwd "/foo/quux"
       (do-something))

   Think about what would happen if WITH-CWD were a function.  (This
   is probably obvious, but bear with me.)  The arguments would be
   evaluated from left to right (Hyperspec section 3.1.2.1.2.3), and
   the function WITH-CWD would receive two arguments: the namestring
   and the *result* of evaluating (DO-SOMETHING).  Oops!  We want to
   delay evaluation of (DO-SOMETHING) until the current working
   directory is bound, but we can't seem to do that using functional
   semantics.

   When functional semantics won't get the job done, this is usually
   the best sign that a macro is appropriate.

   Another way to think of macros is as programs that transform one
   piece of source code into another, but that just begs the
   question: why do you want to transform the code in the first
   place?  Usually, it's because the best way to write the code --
   by "best", I mean the representation that reflects the problem
   most faithfully, that clarifies the intent of the code, and so on
   -- is to use syntax that does not have functional semantics.  In
   that case, you need a macro to transform your code into something
   that can be executed.

   You should *not* use a macro instead of a function if your only
   reason is to get in-line expansion of the code.  Common Lisp
   provides the INLINE declaration and/or DEFINE-COMPILER-MACRO for
   that purpose (although implementations are allowed to ignore
   INLINE declarations).

2. Why use both a macro and a function?

   There are several reasons, some or all of which may be relevant
   in any particular situation.

   First, it allows you to change the implementation of the function
   without recompiling the source code that uses the macro.  For
   example, suppose you need to move your CWD code to a Lisp
   implementation that uses CHDIR instead of CHANGE-DIRECTORY.  If
   the implementation uses only a macro, then you must modify the
   macro, recompile it, then recompile every piece of code that uses
   the macro.  OTOH, if you split the implementation into a macro
   and a function, then you only need to modify and recompile the
   function.  As long as the expansion of the macro doesn't change,
   you don't need to recompile the rest of the source code.

   Second, if you make the macro as simple as possible, so that its
   sole purpose is to perform the minimal amount of rewriting needed
   to achieve functional semantics, then you can often avoid some or
   all of the pitfalls associated with macros: multiple evaluation,
   variable capture, etc.

   Third, splitting the implementation has the benefit of providing
   both a macro interface and a functional interface to your code,
   so that you can use whichever is most convenient in a particular
   situation.

   Lastly, it avoids bloating the compiled code with multiple
   copies of a large expansion.  These days, this is probably less
   of an issue, but imagine a recursive macro implementation of the
   Fibonacci function!

As you gain experience with Common Lisp, you'll undoubtedly write
many macros.  I must have written a huge number of iteration macros
over the years, sometimes for built-in data structures, but often
for custom ones.  Here's a representative one:

(defmacro do-hash-table ((key value hash-table &optional return-value)
                         &body body)
  "Iterates over each key and value pair in the given hash table."
  (let ((function '#:do-hash-table-body))
    `(block nil
       (flet ((,function (,key ,value)
                ,@body))
         (declare (dynamic-extent #',function))
         (maphash #',function ,hash-table)
         ,return-value))))

It displays several features that have proved useful.  The expansion
uses (BLOCK NIL ...) so that the (RETURN) is useful within the body.
The optional return value is often very convenient if it fits within
your chosen syntax.  The body code appears within a form that allows
declarations (in this case, FLET).  Together, these features support
the following types of usage:

(defun every-widget-works-p (hash-table)
  "Returns T iff every entry in the given hash table works."
  (do-hash-table (name widget hash-table t)
    (declare (ignore name))
    (when (not (widget-works-p widget))
      (return nil))))

Happy Lisping!  :)


Phil Stubblefield
Rockwell Palo Alto Laboratory                               206/655-3204
http://www.rpal.rockwell.com/~phil                ····@rpal.rockwell.com
From: Friedrich Dominicus
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <87vgyru2bv.fsf@q-software-solutions.com>
Thanks for this detailed and very understandable answer.

Friedrich


-- 
for e-mail reply remove all after .com 
From: ·······@neodesic.com
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <m3d7kwx3d7.fsf@localhost.localdomain>
Phil Stubblefield <····@rpal.rockwell.com> writes:
> 
> It displays several features that have proved useful.  The expansion
> uses (BLOCK NIL ...) so that the (RETURN) is useful within the body.
> The optional return value is often very convenient if it fits within
> your chosen syntax.  The body code appears within a form that allows
> declarations (in this case, FLET).  Together, these features support
> the following types of usage:
> 
> (defun every-widget-works-p (hash-table)
>   "Returns T iff every entry in the given hash table works."
>   (do-hash-table (name widget hash-table t)
>     (declare (ignore name))
>     (when (not (widget-works-p widget))
>       (return nil))))

Nice flet and block tricks.  If the FAQ were being updated, this might
be a nice thing to add to it.
From: Paolo Amoroso
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <xFdgOVWYX=WRU2wdp5yU4U1o5hhV@4ax.com>
On 02 Jul 2000 04:56:04 -0500, ·······@neodesic.com wrote:

> Nice flet and block tricks.  If the FAQ were being updated, this might
> be a nice thing to add to it.

The new CLiki site by Daniel Barlow is intended also as a repository useful
tips and information, and anybody has write access. Give it a try:

  http://ww.telent.net/cliki/


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/
From: Paul Foley
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <m23dlw23rx.fsf@mycroft.actrix.gen.nz>
On 29 Jun 2000 08:57:02 +0200, Friedrich Dominicus wrote:

>> I probably would have written your examples as follows (also
>> omitting doc strings):
>> 
>> (defmacro with-cwd ((directory) &body body)
>>   `(call-with-cwd ,directory #'(lambda () ,@body)))
>> 
>> (defun call-with-cwd (directory thunk)
>>   (let ((old-wd (pwd)))
>>     (unwind-protect
>>         (progn
>>           (change-directory directory)
>>           (funcall thunk))
>>       (change-directory old-wd))))

> It is not clear to me why I should use both. I was thinking either a
> macro or a functon would be enough. In ON Lisp I found often the

Nobody said you _should_ use both.

Having the macro expand into a function helps avoid the "problem" of
variable capture, and (more important, in reality) multiple
evaluation.  In other words, you don't need a gensym.  It also has the
advantage of letting you change the function definition without having
to recompile everything that uses the macro.  [And it avoids bloating
your compiled code with 50 copies of the full expansion]

> Another point which was not stated clearly is what seems to be the
> "better" approach. Writing it down as a function or a macro

In this case, a macro is clearly better, because you can write
natural-looking code using &body, rather than having to use thunks.
In cases where you actually have a choice, a function is almost always
what you want.

-- 
Nomina stultorum in parietibus et portis semper videmus.      -- Cicero

(setq reply-to
  (concatenate 'string "Paul Foley " "<mycroft" '(··@) "actrix.gen.nz>"))
From: Friedrich Dominicus
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <87g0pw685i.fsf@q-software-solutions.com>
> 
> Having the macro expand into a function helps avoid the "problem" of
> variable capture, and (more important, in reality) multiple
> evaluation.  In other words, you don't need a gensym.

Is there a problem with gensym? 

>  It also has the
> advantage of letting you change the function definition without having
> to recompile everything that uses the macro.  [And it avoids bloating
> your compiled code with 50 copies of the full expansion]

I think this a good reason.
> 
> > Another point which was not stated clearly is what seems to be the
> > "better" approach. Writing it down as a function or a macro
> 
> In this case, a macro is clearly better, because you can write
> natural-looking code using &body, rather than having to use thunks.
> In cases where you actually have a choice, a function is almost always
> what you want.

Sorry I do not understand this. It seems as if I can use a function
here, anyway you recommend using a macro, could you explain that a bit
more please

Regards
Friedrich

> 
> -- 
> Nomina stultorum in parietibus et portis semper videmus.      -- Cicero
> 
> (setq reply-to
>   (concatenate 'string "Paul Foley " "<mycroft" '(··@) "actrix.gen.nz>"))

-- 
for e-mail reply remove all after .com 
From: Joe Marshall
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <3dlwsbsg.fsf@alum.mit.edu>
Friedrich Dominicus <·····@q-software-solutions.com> writes:

> > Having the macro expand into a function helps avoid the "problem" of
> > variable capture, and (more important, in reality) multiple
> > evaluation.  In other words, you don't need a gensym.
> 
> Is there a problem with gensym? 

Only if you forget to use it.  Then it will almost always work anyway,
except sometimes.  The `functional' definition doesn't have one to
forget to use.
From: Barry Margolin
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <AqJ65.7$db4.388@burlma1-snr2>
In article <··············@q-software-solutions.com>,
Friedrich Dominicus  <·····@q-software-solutions.com.NO-spam> wrote:
>> 
>> Having the macro expand into a function helps avoid the "problem" of
>> variable capture, and (more important, in reality) multiple
>> evaluation.  In other words, you don't need a gensym.
>
>Is there a problem with gensym? 

It's one more complication for macro writers to have to remember to deal
with.

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Friedrich Dominicus
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <877lb85x98.fsf@q-software-solutions.com>
Barry Margolin <······@genuity.net> writes:

> >
> >Is there a problem with gensym? 
> 
> It's one more complication for macro writers to have to remember to deal
> with.

I've t admit I feel that it's easy to remember better using gemsym in
macros than thinking about what happens if I do not. So I would think
while using gensym I'm on the safe side. That's usually more than
enough for me ;-)

Regards
Friedrich

-- 
for e-mail reply remove all after .com 
From: Barry Margolin
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <cXL65.30$db4.629@burlma1-snr2>
In article <··············@q-software-solutions.com>,
Friedrich Dominicus  <·····@q-software-solutions.com.NO-spam> wrote:
>Barry Margolin <······@genuity.net> writes:
>
>> >
>> >Is there a problem with gensym? 
>> 
>> It's one more complication for macro writers to have to remember to deal
>> with.
>
>I've t admit I feel that it's easy to remember better using gemsym in
>macros than thinking about what happens if I do not. So I would think
>while using gensym I'm on the safe side. That's usually more than
>enough for me ;-)

Of course, learning new paradigms is harder than continuing what you're
used to.  Writing macros like that is fine, and many people have not
adopted the other style.

But as macros get more complicated, the advantages of using the helper
function increase.  In addition to avoiding the gensym, it also makes it
easier to avoid problems with order of evaluation and multiple evaluation.
And as someone pointed out, it allows you to redefine how the macro works
without having to recompile all the callers.

There are some macros that can't be recast into the style of calling a
helper function easily, such as SETF.  But most WITH-xxx macros tend to be
good candidates for this, so it may be a good idea to get used to that
style.

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Paul Foley
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <m2wvj8zkux.fsf@mycroft.actrix.gen.nz>
On 29 Jun 2000 13:25:45 +0200, Friedrich Dominicus wrote:

>> Having the macro expand into a function helps avoid the "problem" of
>> variable capture, and (more important, in reality) multiple
>> evaluation.  In other words, you don't need a gensym.

> Is there a problem with gensym? 

No.

>> In this case, a macro is clearly better, because you can write
>> natural-looking code using &body, rather than having to use thunks.
>> In cases where you actually have a choice, a function is almost always
>> what you want.

> Sorry I do not understand this. It seems as if I can use a function
> here, anyway you recommend using a macro, could you explain that a bit
> more please

You can't use a function.  Or rather, you can use a function, but only
if you're willing to change the syntax by requiring a (user-supplied,
not macro-generated) thunk.  This is ugly and unnatural.  What I meant
is that when you have to make a choice to use either a function or
macro with the same syntax and semantics -- which is to say, you're
only using a macro to get a notional function expanded in-line -- you
want a function.

-- 
Nomina stultorum in parietibus et portis semper videmus.      -- Cicero

(setq reply-to
  (concatenate 'string "Paul Foley " "<mycroft" '(··@) "actrix.gen.nz>"))
From: Friedrich Dominicus
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <873dlw5wzh.fsf@q-software-solutions.com>
Paul Foley <·······@actrix.gen.nz> writes:

> 
> You can't use a function.  Or rather, you can use a function, but only
> if you're willing to change the syntax by requiring a (user-supplied,
> not macro-generated) thunk.  

This was the starting point I had this function

(defun directory-files (&optional dir (pwd))
  (let* ((ls-cmd (concatenate 'string "ls" " " dir))
        (ls-stream (system:open-pipe ls-cmd))
        (dir-list '()))
    (do* ((file (read-line ls-stream nil) (read-line ls-stream nil)))
         ((null file) (nreverse dir-list))
      (push file dir-list))))


With that function
(with-cwd "/tmp" 'directory-files) worked and I don't feel that this
is ugly and unnatural. But I may feel under other cicumstances and as
I understood this will not happen with the suggested macro form using
&body. 


Regards
Friedrich


-- 
for e-mail reply remove all after .com 
From: Barry Margolin
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <h2M65.31$db4.712@burlma1-snr2>
In article <··············@q-software-solutions.com>,
Friedrich Dominicus  <·····@q-software-solutions.com.NO-spam> wrote:
>With that function
>(with-cwd "/tmp" 'directory-files) worked and I don't feel that this
>is ugly and unnatural. But I may feel under other cicumstances and as
>I understood this will not happen with the suggested macro form using
>&body. 

It's fine when you're calling a named function that already exists, but
when you're using one-shot code it gets uglier because of the LAMBDA, i.e.

(with-cwd "/tmp"
          (lambda ()
            (do-this to-that)
            (do-that x y)
            (do-something-else)))

compared to:

(with-cwd ("/tmp")
  (do-this to-that)
  (do-that x y)
  (do-something-else))

Note that the naming style WITH-xxx has become traditionally associated
with macros of this style -- notice all the WITH-xxx macros that are
standard in Common Lisp.  So if you're not going to use this style, you
shouldn't use that naming convention (just as you should only use *var*
names for special variables), since it will confuse programmers who use
your code.  Since it's a Scheme style of programming, you should use the
Scheme naming convention, call-with-cwd.  Also, since it doesn't gain
anything by being a macro, it should probably be a function (also as in
Scheme).

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Friedrich Dominicus
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <87og4ju1mn.fsf@q-software-solutions.com>
Barry Margolin <······@genuity.net> writes:

> In article <··············@q-software-solutions.com>,
> Friedrich Dominicus  <·····@q-software-solutions.com.NO-spam> wrote:
> >With that function
> >(with-cwd "/tmp" 'directory-files) worked and I don't feel that this
> >is ugly and unnatural. But I may feel under other cicumstances and as
> >I understood this will not happen with the suggested macro form using
> >&body. 
> 
> It's fine when you're calling a named function that already exists, but
> when you're using one-shot code it gets uglier because of the LAMBDA, i.e.
> 
> (with-cwd "/tmp"
>           (lambda ()
>             (do-this to-that)
>             (do-that x y)
>             (do-something-else)))

I agree that this is not what I would easily understood and because of
this and other good replies I think that using a macro wrapper around
a function is the nicest solution here.

> 
> compared to:
> 
> (with-cwd ("/tmp")
>   (do-this to-that)
>   (do-that x y)
>   (do-something-else))
> 
> Note that the naming style WITH-xxx has become traditionally associated
> with macros of this style -- notice all the WITH-xxx macros that are
> standard in Common Lisp.  

This was the starting point why I asked this question. What reasons
are there why this things are written as macros. I guess I understand
this better than before.


>So if you're not going to use this style, you
> shouldn't use that naming convention (just as you should only use *var*
> names for special variables), since it will confuse programmers who use
> your code.  Since it's a Scheme style of programming, you should use the
> Scheme naming convention, call-with-cwd.  Also, since it doesn't gain
> anything by being a macro, it should probably be a function (also as in
> Scheme).
I was playing around a bit with interfacing to the Unix System I'm
working on and I've SCSH installed here, a lot of people have made
good points why one should prefer Common Lisp and I have to say that
for me the large standardized library makes the best point. 

I just can lood around a bit and surly there will be a function which
fits for what I want to do now. And I can often be sure that it will
work with other Common Lisps too. Of course this won't work for
interfacing to the Operating System but Common Lisp provided
facilities to handle that too.

And
because I know a bit OO I feel I'm on the "better" side using Common
Lisp for any more large scale programming. What I especially like is
the environments at hand which allow me to explore the system if I
found something of interest. I don't have knows this facilities before
as "integral" part of the programming approach. Because my type of
programming is most of the time starting form a small kernel (which
should work obviously) and adding just a small piece of extra
functionality a time, I like the Common Lisp approach especially.

The other area in which I found such convenient environments can be
found in Smalltalk. And I do think I understand more and more why
people prefer this sort of Programming Environment.

Best regards
Friedrich

-- 
for e-mail reply remove all after .com 
From: Rainer Joswig
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <rainer.joswig-DCFCC2.22310829062000@news.is-europe.net>
In article <··············@mycroft.actrix.gen.nz>, Paul Foley 
<·······@actrix.gen.nz> wrote:

> You can't use a function.  Or rather, you can use a function, but only
> if you're willing to change the syntax by requiring a (user-supplied,
> not macro-generated) thunk.  This is ugly and unnatural.

This is just a matter of style. I have written code with both
approaches.

The non-macro version has several advantages:

- easier combination via higher-order functions
  -> functional approach is more elegant

- greatly increased debuggability -> you see stack frames,
  and you can recompile piece by piece. Try to let
  a less experienced Lisp programmer debug code which
  is generated by macros (which may be generated by macros)

- less code bloat

- less ways to introduce errors in code

- less syntactic sugar

-- 
Rainer Joswig, BU Partner,
ISION Internet AG, Steinh�ft 9, 20459 Hamburg, Germany
Tel: +49 40 3070 2950, Fax: +49 40 3070 2999
Email: ····················@ision.net WWW: http://www.ision.net/
From: Johan Kullstam
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <uem5hmzya.fsf@res.raytheon.com>
Friedrich Dominicus <·····@q-software-solutions.com> writes:

> I'm trying getting a bit more familiar with Common Lisp and write some
> small piecs of code. I come along with this ones:
> (defun with-cwd (dir thunk)
>   (let ((old-wd (pwd)))
>     (unwind-protect
>         (progn
>           (change-directory dir)
>           (funcall thunk))
>       (change-directory old-wd))))
> 
> (defmacro with-cwd-m (dir thunk)
>   (let ((old-wd (gensym)))
>     `(let ((,old-wd (pwd)))
>        (declare (dynamic-extent ,old-wd))
>        (unwind-protect
>            (progn
>              (change-directory ,dir)
>              (funcall ,thunk))
>          (change-directory ,old-wd)))))
> 
> comments are ommitted frankly here.

i am not sure about the utility of the function.  most things of this
nature are macros.

in the macro, why not follow WITH-OPEN-FILE and do

(defmacro with-cwd-m (dir &body body)

then instead of the (funcall ,thunk), use a splice ,@body.

then you can do

(with-cwd-m some-dir
  (function 1)
  ...
  (...))

which seems to be a reasonable way to invoke something like this.

> Now my questions:
> - all the other with-... functions I found in Common Lisp are macros,
> so I think this one might be better written as a macro. Can someone
> explain, why the macro may be the better-choice.

because macro are automated code writers.  you are basically trying to
stamp out a code template with a minimum of fuss.

> - I found the line with (declare (dynamic-exte... in On Lisp page 149,
> it seems to me that using it might be ok here too. But I'm not sure,
> can someone explain why it might be good or if I better should omitt
> it.
> 
> 
> 
> 
> Now a somewhat related question but a bit away. I want the 
> first parameter of the funtion/macro be a String and the second to be
> a function with no parameter.

the macro method using &body finds problems at load, macro-expand,
compile time rather than run time.  this solves your problem nicely by
avoiding it altogether.

-- 
johan kullstam l72t00052
From: Tim Moore
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <8jdi0i$5ms$0@216.39.145.192>
On 28 Jun 2000, Friedrich Dominicus wrote:

> I'm trying getting a bit more familiar with Common Lisp and write some
> small piecs of code. I come along with this ones:
> (defun with-cwd (dir thunk)
>   (let ((old-wd (pwd)))
>     (unwind-protect
>         (progn
>           (change-directory dir)
>           (funcall thunk))
>       (change-directory old-wd))))
> 
> (defmacro with-cwd-m (dir thunk)
>   (let ((old-wd (gensym)))
>     `(let ((,old-wd (pwd)))
>        (declare (dynamic-extent ,old-wd))
>        (unwind-protect
>            (progn
>              (change-directory ,dir)
>              (funcall ,thunk))
>          (change-directory ,old-wd)))))
> 
> Now my questions:
> - all the other with-... functions I found in Common Lisp are macros,
> so I think this one might be better written as a macro. Can someone
> explain, why the macro may be the better-choice.

More convenient syntax, though it's not apparent in the way you wrote it.
If you wrote your macro like this (using with-cwd, which you've helpfully 
defined :) :

(defmacro with-cwd-m ((dir) &body body)
  `(with-cwd ,dir #'(lambda () ,@body)))

Then when using this you could write:

(with-cmd-m ("/usr/home/foo")
  (some-code)
  (some-other-code))

instead of the slightly more awkward:

(with-cmd "/usr/home/foo"
	  #'(lambda ()
	      (some-code)
	      (some-other-code)))

There may also be performance differences between a functional approach
and a macro approach.  The functional version is probably going to create
a closure whereas your macro version might not and a macro that dispensed
with the thunk certainly wouldn't.

> 
> - I found the line with (declare (dynamic-exte... in On Lisp page 149,
> it seems to me that using it might be ok here too. But I'm not sure,
> can someone explain why it might be good or if I better should omitt
> it.

I wouldn't mess with it unless you know what you're doing.  It in effect
says that the storage allocated by the result of (pwd) isn't used
outside of the dynamic extent of the enclosing let and can therefore be
allocated on the stack.  In order for it to make any difference here the
compiler would have to have special knowledge about pwd, or pwd would have
to be tuned in some low-level way.  Not very likely.
 
> I can put in a (check-type dir string) and this will go through but I
> can not find out how to state that thunk should be a function with no
> parameter.
> 
> I found this in the Hyperspec:
> The list form of the function type-specifier can be used only for
> declaration and not for discrimination. 
> 
> The latter suggests that I may out of luck, but I do not know if I
> understand it correctly.

More or less.  You can write a declaration for the function type and at
high safety levels an implementation might check that the argument type is
correct. This boils down to doing a check-type or equivalent at runtime,
and if the implementation if fact doesn't distinguish functions of
different arguments, then you're out of luck.  Some implmentations might
be able to use the type declaration to to type checking at compile time in
some cases.

Tim
From: Erik Naggum
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <3171212063253918@naggum.no>
* Friedrich Dominicus <·····@q-software-solutions.com>
| I'm trying getting a bit more familiar with Common Lisp and write some
| small piecs of code. I come along with this ones:
| 
| (defun with-cwd (dir thunk)
|   (let ((old-wd (pwd)))
|     (unwind-protect
|         (progn
|           (change-directory dir)
|           (funcall thunk))
|       (change-directory old-wd))))
| 
| (defmacro with-cwd-m (dir thunk)
|   (let ((old-wd (gensym)))
|     `(let ((,old-wd (pwd)))
|        (declare (dynamic-extent ,old-wd))
|        (unwind-protect
|            (progn
|              (change-directory ,dir)
|              (funcall ,thunk))
|          (change-directory ,old-wd)))))
| 
| comments are ommitted frankly here.

  I'll supply my own: This is Scheme in Common Lisp guise.  Bad karma.

  In Common Lisp, one generally uses bodies in macros, not thunks.
  Thunks are very useful when you don't have macros in the first place.

(defmacro with-cwd (dir &body body)
  (let ((old-wd (gensym)))
    `(let ((,old-wd (pwd)))
       (unwind-protect
           (progn
             (change-directory ,dir)
	     ,@body)
         (change-directory ,old-wd)))))

| - I found the line with (declare (dynamic-exte... in On Lisp page
| 149, it seems to me that using it might be ok here too. But I'm not
| sure, can someone explain why it might be good or if I better should
| omitt it.

  I see no use for it, but that doesn't mean it won't help a compiler
  somewhere decide to do something useful with it.

| Now a somewhat related question but a bit away.  I want the  first
| parameter of the funtion/macro be a String and the second to be a
| function with no parameter.

  I think you're getting a simpler, more readable, and better
  fulfillment of that desire by embedding a body in the macro
  expansion rather than calling a thunk.

  On a side-note: I dislike Scheme more every time somebody fails to
  understand that Scheme was designed to experiment with programming
  methodologies and even paradigms and copies some of its ways as if
  they were gospel.  That _really_ bugs me, mostly because it is _so_
  har do undo such concrete-bound learning -- people who apparently
  have no experience or training in getting the abstract picture get
  so _obsessive_ about particulars, and some of those particulars in
  Scheme are just not good ideas to take with you outside of Scheme.

#:Erik
-- 
  If this is not what you expected, please alter your expectations.
From: Ray Blaak
Subject: Re: Macros vs Functions and a question about check-type
Date: 
Message-ID: <m3hfad3ssg.fsf@ns48.infomatch.bc.ca>
Erik Naggum <····@naggum.no> writes:
> * Friedrich Dominicus <·····@q-software-solutions.com>
> | [(defun with-cwd ...) vs (defmacro with-cwd-m ...)
> | comments are ommitted frankly here.
> 
>   I'll supply my own: This is Scheme in Common Lisp guise.  Bad karma.
> 
>   In Common Lisp, one generally uses bodies in macros, not thunks.
>   Thunks are very useful when you don't have macros in the first place.

The macro solution with a body is better for Scheme as well, simply because the
usage is more natural, simpler, and robust for users.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
·····@infomatch.com                            The Rhythm has my soul.