From: phr
Subject: Editor support for refactoring with macros?
Date: 
Message-ID: <1167094946.247660.98210@48g2000cwx.googlegroups.com>
Suppose I have a bunch of code with obviously redundant patterns in it.
So I define an obvious simple macro to factor out some of the
redundancy.  Shouldn't a smart editor that understands lisp be able to
automatically convert my redundant code to use the new macro?

Here's an example taken from my (possibly silly) attempt to replace
Microsoft Money with some simple lisp:

A typical purchase from my main checking account might look like this:

(purchk 20060101 880 "QFC"
  :tax-sales 244
  :household (- 880 244) "Batteries")

20060101 is a date, for which I'll worry about finding a better
representation later.

880 is the total amount of the transaction charged to checking.  I'm
entering money amounts in integer pennies for now.  I may look for a
fixed-decimal representation someday.

QFC is the payee, the chain where I do most of my grocery shopping.

It says I paid $2.44 in sales tax, which seems unreasonably high, and
the rest for batteries, charged as household expense.  As I recall
there was a storm and power failure last January 1st.

I had most of a year's worth of transactions entered in that style,
when I finally decided to factor out some of the repetition:

(defmacro qfc (date total &body body)
  `(purchk ,date ,total "QFC"
      ,@body))

So that example transaction would refactor as:

(qfc 20060101 880
  :tax-sales 244
  :household (- 880 244) "Batteries")

Ok.  Very simple.  Baby stuff.

But now I've been converting my old code and keep thinking a lisp
function ought to be able to accept my macro definition and my existing
code, and spit out my code automatically converted to use the macro
where appropriate.

Surely I'm not the first person to think of this.   Do the commercial
lisp implementations have this already?  How hard would it be to code
it up in elisp+slime?

From: Pascal Bourguignon
Subject: Re: Editor support for refactoring with macros?
Date: 
Message-ID: <87y7ouvgnw.fsf@thalassa.informatimago.com>
"phr" <········@gmail.com> writes:

> Suppose I have a bunch of code with obviously redundant patterns in it.
> So I define an obvious simple macro to factor out some of the
> redundancy.  Shouldn't a smart editor that understands lisp be able to
> automatically convert my redundant code to use the new macro?
>
> Here's an example taken from my (possibly silly) attempt to replace
> Microsoft Money with some simple lisp:
>
> A typical purchase from my main checking account might look like this:
>
> (purchk 20060101 880 "QFC"
>   :tax-sales 244
>   :household (- 880 244) "Batteries")
>
> 20060101 is a date, for which I'll worry about finding a better
> representation later.
>
> 880 is the total amount of the transaction charged to checking.  I'm
> entering money amounts in integer pennies for now.  I may look for a
> fixed-decimal representation someday.
>
> QFC is the payee, the chain where I do most of my grocery shopping.
>
> It says I paid $2.44 in sales tax, which seems unreasonably high, and
> the rest for batteries, charged as household expense.  As I recall
> there was a storm and power failure last January 1st.
>
> I had most of a year's worth of transactions entered in that style,
> when I finally decided to factor out some of the repetition:
>
> (defmacro qfc (date total &body body)
>   `(purchk ,date ,total "QFC"
>       ,@body))
>
> So that example transaction would refactor as:
>
> (qfc 20060101 880
>   :tax-sales 244
>   :household (- 880 244) "Batteries")
>
> Ok.  Very simple.  Baby stuff.
>
> But now I've been converting my old code and keep thinking a lisp
> function ought to be able to accept my macro definition and my existing
> code, and spit out my code automatically converted to use the macro
> where appropriate.
>
> Surely I'm not the first person to think of this.   Do the commercial
> lisp implementations have this already?  How hard would it be to code
> it up in elisp+slime?

The first idea would be:

M-x replace-regexp RET (purchk \(.*\) "QFC" \(.*\)) RET (qfc \1 \2) RET

but indeed, since the forms are not regular expressions, this cannot
work in most cases.


So what I do is:

(replace-sexps "source.lisp" 
      (lambda (sexp)
           (if (eq (car sexp) 'purchk)
               `(qfc (second sexp) (third sexp) "QFC" (cdddr sexp))
               sexp))
      :deeply t :atoms nil)

http://darcs.informatimago.com/darcs/public/emacs/pjb-sources.el
http://darcs.informatimago.com/darcs/public/emacs/

Well actually, it should work ok on emacs lisp sources, but on Common
Lisp sources, there may be some problems relative to reader macros.
I've got some code in 
http://darcs.informatimago.com/darcs/public/lisp/common-lisp/source.lisp
but it's incomplete (I've not implemented most of the standard reader
macros yet).

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

READ THIS BEFORE OPENING PACKAGE: According to certain suggested
versions of the Grand Unified Theory, the primary particles
constituting this product may decay to nothingness within the next
four hundred million years.
From: phr
Subject: Re: Editor support for refactoring with macros?
Date: 
Message-ID: <1167178715.735902.327400@48g2000cwx.googlegroups.com>
Pascal Bourguignon wrote:

> The first idea would be:
>
> M-x replace-regexp RET (purchk \(.*\) "QFC" \(.*\)) RET (qfc \1 \2) RET
>
> but indeed, since the forms are not regular expressions, this cannot
> work in most cases.>
>
> So what I do is:
>
> (replace-sexps "source.lisp"
>       (lambda (sexp)
>            (if (eq (car sexp) 'purchk)
>                `(qfc (second sexp) (third sexp) "QFC" (cdddr sexp))
>                sexp))
>       :deeply t :atoms nil)
>
> http://darcs.informatimago.com/darcs/public/emacs/pjb-sources.el
> http://darcs.informatimago.com/darcs/public/emacs/
>
> Well actually, it should work ok on emacs lisp sources, but on Common
> Lisp sources, there may be some problems relative to reader macros.
> I've got some code in
> http://darcs.informatimago.com/darcs/public/lisp/common-lisp/source.lisp
> but it's incomplete (I've not implemented most of the standard reader
> macros yet).
>

Cool code, Pascal.

It seems to me that it ought to be possible to generate your
transformer lambda expression directly from the defmacro form, though
now that I've looked at your code, I see that's the easy part.

Do experienced Lisp programmers use transformation tools like that a
lot, or are they simply better than me at spotting the need for a macro
early?  I suspect the latter.  Also they seem to be much better with
emacs than me.
From: Pascal Bourguignon
Subject: Re: Editor support for refactoring with macros?
Date: 
Message-ID: <87y7outbjt.fsf@thalassa.informatimago.com>
"phr" <········@gmail.com> writes:

> Pascal Bourguignon wrote:
>
>> The first idea would be:
>>
>> M-x replace-regexp RET (purchk \(.*\) "QFC" \(.*\)) RET (qfc \1 \2) RET
>>
>> but indeed, since the forms are not regular expressions, this cannot
>> work in most cases.>
>>
>> So what I do is:
>>
>> (replace-sexps "source.lisp"
>>       (lambda (sexp)
>>            (if (eq (car sexp) 'purchk)
>>                `(qfc (second sexp) (third sexp) "QFC" (cdddr sexp))
>>                sexp))
>>       :deeply t :atoms nil)
>>
>> http://darcs.informatimago.com/darcs/public/emacs/pjb-sources.el
>> http://darcs.informatimago.com/darcs/public/emacs/
>>
>> Well actually, it should work ok on emacs lisp sources, but on Common
>> Lisp sources, there may be some problems relative to reader macros.
>> I've got some code in
>> http://darcs.informatimago.com/darcs/public/lisp/common-lisp/source.lisp
>> but it's incomplete (I've not implemented most of the standard reader
>> macros yet).
>>
>
> Cool code, Pascal.
>
> It seems to me that it ought to be possible to generate your
> transformer lambda expression directly from the defmacro form, though
> now that I've looked at your code, I see that's the easy part.
>
> Do experienced Lisp programmers use transformation tools like that a
> lot, or are they simply better than me at spotting the need for a macro
> early?  I suspect the latter.  Also they seem to be much better with
> emacs than me.

I must confess that I don't use it a lot.  I've used it twice or
thrice to do some such transforms, (or one of the variants to search
for specific forms).  Perhaps the most often use I make of this code
is in insert-generics which scans the source for DEFMETHOD forms and
inserts corresponding DEFGENERIC forms.

But not for plain "refactoring": as soon as a pattern emerge (which
may be as soon as I type twice the same thing), I usually factor it
out immediately, be it in a function or a macro depending on the
cases.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS d? s++:++ a+ C+++ UL++++ P--- L+++ E+++ W++ N+++ o-- K- w--- 
O- M++ V PS PE++ Y++ PGP t+ 5+ X++ R !tv b+++ DI++++ D++ 
G e+++ h+ r-- z? 
------END GEEK CODE BLOCK------