From: ·········@gmail.com
Subject: Can lisp macro do in place code expansion?
Date: 
Message-ID: <1176694908.292564.116390@n76g2000hsh.googlegroups.com>
hi

Can lisp macro do in place code expansion?
like:

(make-list 5 'one-copy-code)
=>
(one-copy-code one-copy-code one-copy-code one-copy-code one-copy-
code)

thanks.

(I will switch if lisp can do this.)

From: Dan Bensen
Subject: Re: Can lisp macro do in place code expansion?
Date: 
Message-ID: <evuucp$t44$1@wildfire.prairienet.org>
·········@gmail.com wrote:
> Can lisp macro do in place code expansion?
> (make-list 5 'one-copy-code)
> =>
> (one-copy-code one-copy-code one-copy-code one-copy-code one-copy-
> code)

Do you mean code to be executed?
You don't need a macro just to create a list.

> (defmacro do5 (form)
>   (let ((forms '()))
>     (dotimes (n 5) (push form forms))
>     `(progn ,@forms)))

* (macroexpand-1 '(do5 (write-line "I will not code in class.")))
(PROGN
  (WRITE-LINE "I will not code in class.")
  (WRITE-LINE "I will not code in class.")
  (WRITE-LINE "I will not code in class.")
  (WRITE-LINE "I will not code in class.")
  (WRITE-LINE "I will not code in class."))

* (do5 (write-line "I will not code in class."))
I will not code in class.
I will not code in class.
I will not code in class.
I will not code in class.
I will not code in class.

There are also simpler ways of doing this particular example.

-- 
Dan
www.prairienet.org/~dsb/
From: D Herring
Subject: Re: Can lisp macro do in place code expansion?
Date: 
Message-ID: <-rmdnWiEYe-hnb7bnZ2dnUVZ_uWlnZ2d@comcast.com>
·········@gmail.com wrote:
> Can lisp macro do in place code expansion?
> like:
> 
> (make-list 5 'one-copy-code)
> =>
> (one-copy-code one-copy-code one-copy-code one-copy-code one-copy-
> code)
> 
> thanks.
> 
> (I will switch if lisp can do this.)
> 

Here's your (if student homework answer):

(defmacro copies (n item)
    (when (> n 0)
      `(cons ,item (copies ,(1- n) ,item))))

But that's the least of what a Lisp macro can do.  Lisp macros can do 
almost anything lisp functions can do; the only difference is that 
macros execute at compile time and functions execute at run time, except 
when executed by macros.  For example, here's an interactive macro that 
"helps" the user define new functions:

(defmacro readfun ()
   (let ((name (progn (princ "Enter the function name: ")
		     (read)))
	(args (progn (princ "Enter the argument list: ")
		     (read)))
	(desc (progn (princ "Enter the function comment: ")
		     (read-line)))
	(body (progn (format t "Enter the function body.~%")
		     (format t "(blank line to finish)~%")
		     (let ((input nil))
		       (princ "line 1: ")
		       (do ((line (read-line)
				  (read-line))
			    (n 2 (1+ n)))
			   ((= 0 (length line)))
			 (setf input
			       (append input
				       (list (read-from-string line))))
			 (format t "line ~A: " n))
		       input))))
     `(defun ,name ,args ,desc ,@body)))

Example usage:
(readfun)
Enter the function name: test
Enter the argument list: (x y)
Enter the function comment: this is a test
Enter the function body.
(blank line to finish)
line 1: (format t "x=~A~%" x)
line 2: (format t "y=~A~%" y)
line 3: (format t "x+y=~A~%" (+ x y))
line 4: (+ x y)
line 5:
=> test
(test 3 4)
x=3
y=4
x+y=7
=> 7

- Daniel
From: D Herring
Subject: Re: Can lisp macro do in place code expansion?
Date: 
Message-ID: <Se-dneay_eZ4nL7bnZ2dnUVZ_uCinZ2d@comcast.com>
D Herring wrote:
> ·········@gmail.com wrote:
>> Can lisp macro do in place code expansion?
>> like:
>>
>> (make-list 5 'one-copy-code)
>> =>
>> (one-copy-code one-copy-code one-copy-code one-copy-code one-copy-
>> code)
>>
>> thanks.
>>
>> (I will switch if lisp can do this.)
>>
> 
> Here's your (if student homework answer):
> 
> (defmacro copies (n item)
>    (when (> n 0)
>      `(cons ,item (copies ,(1- n) ,item))))
> 
> But that's the least of what a Lisp macro can do.  Lisp macros can do 
> almost anything lisp functions can do; the only difference is that 
> macros execute at compile time and functions execute at run time, except 
> when executed by macros.  For example, here's an interactive macro that 
> "helps" the user define new functions:
> 
> (defmacro readfun ()

BTW, this was a horrible abuse of macros.  Macros are usually used to 
hide away "boilerplate", repetitive code.  Think of them as a smart 
"search-and-replace" that gets run as your code is compiled.

- Daniel
From: Pascal Bourguignon
Subject: Re: Can lisp macro do in place code expansion?
Date: 
Message-ID: <87fy70h9sx.fsf@voyager.informatimago.com>
D Herring <········@at.tentpost.dot.com> writes:

> D Herring wrote:
>> ·········@gmail.com wrote:
>>> Can lisp macro do in place code expansion?
>>> like:
>>>
>>> (make-list 5 'one-copy-code)
>>> =>
>>> (one-copy-code one-copy-code one-copy-code one-copy-code one-copy-
>>> code)
>>>
>>> thanks.
>>>
>>> (I will switch if lisp can do this.)
>>>
>>
>> Here's your (if student homework answer):
>>
>> (defmacro copies (n item)
>>    (when (> n 0)
>>      `(cons ,item (copies ,(1- n) ,item))))
>>
>> But that's the least of what a Lisp macro can do.  Lisp macros can
>> do almost anything lisp functions can do; the only difference is
>> that macros execute at compile time and functions execute at run
>> time, except when executed by macros.  For example, here's an
>> interactive macro that "helps" the user define new functions:
>>
>> (defmacro readfun ()
>
> BTW, this was a horrible abuse of macros.  Macros are usually used to
> hide away "boilerplate", repetitive code.  Think of them as a smart
> "search-and-replace" that gets run as your code is compiled.

Well such a macro could be used inside a compiler-macro function to
unfold loops, if the compiler of that implementation wasn't able to do
it.

-- 
__Pascal Bourguignon__
http://www.informatimago.com/
http://pjb.ogamita.org/
From: Duane Rettig
Subject: Re: Can lisp macro do in place code expansion?
Date: 
Message-ID: <o0abx5abzr.fsf@gemini.franz.com>
D Herring <········@at.tentpost.dot.com> writes:

> D Herring wrote:
>> ·········@gmail.com wrote:
>>> Can lisp macro do in place code expansion?
>>> like:
>>>
>>> (make-list 5 'one-copy-code)
>>> =>
>>> (one-copy-code one-copy-code one-copy-code one-copy-code one-copy-
>>> code)
>>>
>>> thanks.
>>>
>>> (I will switch if lisp can do this.)
>>>
>> Here's your (if student homework answer):
>> (defmacro copies (n item)
>>    (when (> n 0)
>>      `(cons ,item (copies ,(1- n) ,item))))
>> But that's the least of what a Lisp macro can do.  Lisp macros can
>> do almost anything lisp functions can do; the only difference is
>> that macros execute at compile time and functions execute at run
>> time, except when executed by macros.  For example, here's an
>> interactive macro that "helps" the user define new functions:
>> (defmacro readfun ()
>
> BTW, this was a horrible abuse of macros.

Why?

The rest of your paragraph seems to answer this question, but I'm
asking it anyway, because if this is your reason, I disagree:

>  Macros are usually used to
> hide away "boilerplate", repetitive code.  Think of them as a smart
> "search-and-replace" that gets run as your code is compiled.

No; macros in _other_ languages (including some lisps) are of this
nature.  But since CL macros execute CL code as part of the
macroexpansion process, it is natural to do things like this perfectly
portable and Lispy macro.  Now, please explain to me: how this is an
abuse?

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: D Herring
Subject: Re: Can lisp macro do in place code expansion?
Date: 
Message-ID: <jaSdnZB6ZeZv2bXbnZ2dnUVZ_rCsnZ2d@comcast.com>
Duane Rettig wrote:
> D Herring <········@at.tentpost.dot.com> writes:
> 
>> D Herring wrote:
>>> ·········@gmail.com wrote:
>>>> Can lisp macro do in place code expansion?
>>>> like:
>>>>
>>>> (make-list 5 'one-copy-code)
>>>> =>
>>>> (one-copy-code one-copy-code one-copy-code one-copy-code one-copy-
>>>> code)
>>>>
>>>> thanks.
>>>>
>>>> (I will switch if lisp can do this.)
>>>>
>>> Here's your (if student homework answer):
>>> (defmacro copies (n item)
>>>    (when (> n 0)
>>>      `(cons ,item (copies ,(1- n) ,item))))
>>> But that's the least of what a Lisp macro can do.  Lisp macros can
>>> do almost anything lisp functions can do; the only difference is
>>> that macros execute at compile time and functions execute at run
>>> time, except when executed by macros.  For example, here's an
>>> interactive macro that "helps" the user define new functions:
>>> (defmacro readfun ()
>> BTW, this was a horrible abuse of macros.
> 
> Why?
> 
> The rest of your paragraph seems to answer this question, but I'm
> asking it anyway, because if this is your reason, I disagree:
> 
>>  Macros are usually used to
>> hide away "boilerplate", repetitive code.  Think of them as a smart
>> "search-and-replace" that gets run as your code is compiled.
> 
> No; macros in _other_ languages (including some lisps) are of this
> nature.  But since CL macros execute CL code as part of the
> macroexpansion process, it is natural to do things like this perfectly
> portable and Lispy macro.  Now, please explain to me: how this is an
> abuse?

My pronoun was ambiguous:
"This" was in reference to "readfun"; "readfun" is a poor example of 
macros since it is (a) interactive and (b) doesn't do any useful code 
transforms.

On the other hand, "copies" is a simple example of using a macro to hide 
away repetitive code.

Sorry for the confusion,
Daniel
From: Lars Rune Nøstdal
Subject: Re: Can lisp macro do in place code expansion?
Date: 
Message-ID: <4623010e$0$29073$c83e3ef6@nn1-read.tele2.net>
On Sun, 15 Apr 2007 20:41:48 -0700, dillogimp wrote:

> hi
> 
> Can lisp macro do in place code expansion? like:
> 
> (make-list 5 'one-copy-code)
> =>
> (one-copy-code one-copy-code one-copy-code one-copy-code one-copy- code)

Yes:

  (defmacro repeat-code (num code)
    (loop :repeat num
      :collecting code))


Code like (repeate-code 3 blah) would now be replaced by (blah blah blah)

If `loop' seems scary, one could also do something like:

  (defmacro repeat-code (num code)
    (let ((result nil))
      (dotimes (i num)
        (push code result))
       result))


One can take a look at what the expansion will be:          

  (macroexpand-1 '(repeat-code 5 blah))
  =>
  (blah blah blah blah blah)


..and when using Slime(#1) one can hover the cursor over any macro-call 
and press C-c <enter> to expand it in a "popup window" (pressing q will 
close the window). Also see the section "Finding definitions" in the 
Slime manual. Great stuff. :)


> (I will switch if lisp can do this.)

Welcome. :)


#1: http://common-lisp.net/project/slime/ and http://common-lisp.net/
project/slime/doc/html/Macro-Expansion.html .. (maybe C-c <enter> has 
been deprecated in place for C-c C-m .. it still seems to work here 
though)

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Kent M Pitman
Subject: Re: Can lisp macro do in place code expansion?
Date: 
Message-ID: <ups64rieg.fsf@nhplace.com>
Lars Rune N�stdal <···········@gmail.com> writes:

>   (defmacro repeat-code (num code)
>     (loop :repeat num
>       :collecting code))
>
> Code like (repeate-code 3 blah) would now be replaced by (blah blah blah)

Heh. Of course, since the REPEAT-CODE would occur in an evaluable position,
unless the code was something that was both suitable as a function and
as its own argument, this makes little sense.  (That's a problem with the
apparent problem description, not the proposed answer.  But it's still
a problem.)

At minimum, he probably wants:

 (defmacro repeat-code (num code)
   (check-type num integer "a constant integer, known at macro expansion time")
   `(progn ,@(loop repeat num collect code)))

But in fact, one of these probably more efficient since actually 
making n copies of code is likely to bloat code uselessly.

 (defmacro repeat-code (num code)
   (let ((var (gensym)))
     ;; makes the decision of how many iterations at runtime
     `(loop repeat ,num for ,var = ,code finally (return ,var))))

to get

 (macroexpand-1 '(repeat-code 3 (some-function arg1 arg2)))
 => (LOOP REPEAT 3
          FOR #:G724 = (SOME-FUNCTION ARG1 ARG2)
          FINALLY (RETURN #:G724))

or at least

 (defmacro repeat-code (num code)
   (check-type num integer "a constant integer, known at macro expansion time")
   (let ((fn (gensym)))
     ;; inserts one copy of the code inline, gives it a name
     `(flet ((,fn () ,code))
        ;; then calls it n times, where n is known at macro expansion time
        ,@(loop repeat num collect `(,fn)))))

to get

  (macroexpand-1 '(repeat-code 3 (some-function arg1 arg2)))

  => (FLET ((#:G718 NIL (QUOTE (FOO))))
       (#:G718)
       (#:G718)
       (#:G718))

I'm assuming this either isn't homework or, if it is, that "useful" operators
are usually not allowed in homework (since no one seems to ever teach Lisp
in a way that makes it seem useful) and so these answers probably won't be
accepted by the teacher.  They're just the right thing to actually do.
Sigh.

> If `loop' seems scary, one could also do something like:
> 
>   (defmacro repeat-code (num code)
>     (let ((result nil))
>       (dotimes (i num)
>         (push code result))

(setq code (nreverse code))

Yes, it doesn't make any difference in this case since all the elements
are the same.  But people should be reminded that push is assembling the
information backwards.

>        result))

p.s.

If what is meant by in-place expansion is "replacing the source text",
Common Lisp doesn't do that since you aren't allowed to modify the
program.  It used to be done in earlier dialects of Lisp, but it had
weird semantics that were impossible to compile reliably and that 
we have thankfully moved beyond.  But there are no ill effects I've ever
noticed of not having THAT capability.
From: Lars Rune Nøstdal
Subject: Re: Can lisp macro do in place code expansion?
Date: 
Message-ID: <46231afd$0$29073$c83e3ef6@nn1-read.tele2.net>
On Mon, 16 Apr 2007 01:35:19 -0400, Kent M Pitman wrote:

> I'm assuming this either isn't homework or, if it is, that "useful"
> operators are usually not allowed in homework (since no one seems to
> ever teach Lisp in a way that makes it seem useful) and so these answers
> probably won't be accepted by the teacher.  They're just the right thing
> to actually do. Sigh.

Yeah, I don't think the OP intended his example or that particular idea 
of usage of macros to be useful. I posted the simplest "solution" I could 
think of for his non-realistic example saying "yes, it can".

I forgot about `make-list' though:

  (defmacro repeat-code (num code)
    (make-list num :initial-element code))

..as used by Frank would maybe be simpler than `loop' or `push'. 

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Pascal Bourguignon
Subject: Re: Can lisp macro do in place code expansion?
Date: 
Message-ID: <87zm59gc81.fsf@voyager.informatimago.com>
·········@gmail.com writes:

> hi
>
> Can lisp macro do in place code expansion?
> like:
>
> (make-list 5 'one-copy-code)
> =>
> (one-copy-code one-copy-code one-copy-code one-copy-code one-copy-
> code)
>
> thanks.

That's what macro are designed to do.  Of course they can!


[120]> (defmacro expand (how-many what) (make-list how-many :initial-element what))
EXPAND
[121]> (macroexpand '(expand 5 one-copy-code))
(ONE-COPY-CODE ONE-COPY-CODE ONE-COPY-CODE ONE-COPY-CODE ONE-COPY-CODE) ;
T
[122]> 

But if one-copy-code is code and not data, you'd rather write:


[122]> (defmacro unfold (how-many &body body)
         (cons 'progn (make-list how-many :initial-element `(progn ,@body))))
UNFOLD
[123]> (macroexpand-1 '(unfold 4 
                            (terpri) (princ "start")
                            (do-something) 
                            (terpri) (princ "done; again?")))
(PROGN
 (PROGN (TERPRI) (PRINC "start") (DO-SOMETHING) (TERPRI) (PRINC "done; again?"))
 (PROGN (TERPRI) (PRINC "start") (DO-SOMETHING) (TERPRI) (PRINC "done; again?"))
 (PROGN (TERPRI) (PRINC "start") (DO-SOMETHING) (TERPRI) (PRINC "done; again?"))
 (PROGN (TERPRI) (PRINC "start") (DO-SOMETHING) (TERPRI) (PRINC "done; again?"))) ;
T
[126]> (defun do-something () (terpri) (princ "  something is done."))
DO-SOMETHING
[127]> (unfold 4 
               (terpri) (princ "start")
               (do-something) 
               (terpri) (princ "done; again?"))

start
  something is done.
done; again?
start
  something is done.
done; again?
start
  something is done.
done; again?
start
  something is done.
done; again?
"done; again?"
[128]> 


> (I will switch if lisp can do this.)

Please, do.

-- 
__Pascal Bourguignon__
From: Frank Buss
Subject: Re: Can lisp macro do in place code expansion?
Date: 
Message-ID: <d760pkol946d.1nsx42p3w5rg2$.dlg@40tude.net>
·········@gmail.com wrote:

> Can lisp macro do in place code expansion?
> like:
> 
> (make-list 5 'one-copy-code)
> =>
> (one-copy-code one-copy-code one-copy-code one-copy-code one-copy-
> code)

Yes, make-list is already defined in Common Lisp, but it has a keyword
argument:

CL-USER > (make-list 5 :initial-element 'one-copy-code)
(ONE-COPY-CODE ONE-COPY-CODE ONE-COPY-CODE ONE-COPY-CODE ONE-COPY-CODE)

But I guess you mean with "code expansion" that the generated list would be
used as Lisp code. This is possible, too:

(defmacro make-list-code (number atom)
  (make-list number :initial-element atom))

macroexpand shows you how it will be expanded:

CL-USER > (macroexpand '(make-list-code 5 one-copy-code))
(ONE-COPY-CODE ONE-COPY-CODE ONE-COPY-CODE ONE-COPY-CODE ONE-COPY-CODE)
T

It's not easy to find a working in place code example with this macro :-)

(defparameter one-copy-code 1)

(defun one-copy-code (&rest args)
  (loop for arg in args do (format t "~a~%" arg)))

CL-USER > (make-list-code 5 one-copy-code)
1
1
1
1
NIL

This is possible, because Common Lisp has different name spaces for
functions and variables.

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de