I have a macro called DOCHUNK that I use to piece up a sequence in
order to process smaller pieces. I.e.
(DOCHUNK piece "abcdefgh" 3 (princ piece) (princ " ")))
abc def gh
DOCHUNK is defined as follows:
(defmacro dochunk ((chunk proseq n &key (start 0) end) &body body)
(let ((low (gensym))
(hi (gensym))
(len (gensym))
(vend (gensym)))
`(let* ((,len (length ,proseq))
(,vend (or ,end ,len))
(,chunk))
(do ((,low ,start ,hi)
(,hi (min ,len ,n) (min (+ ,hi ,n) ,len)))
((>= ,low ,vend) (- ,vend ,start))
(setf ,chunk (subseq ,proseq ,low ,hi))
,@body))))
However, for large sequences there is unnecessary copying into a new
variable CHUNK. I would like CHUNK to expand into (SUBSEQ ,PROSEQ ,LOW
,HI) within ,@BODY. Is this possible? Other comments on concept and
code are also welcoming.
--
Jon Haugsand
Norwegian Computing Center, <http://www.nr.no/engelsk/>
<···············@nr.no> Pho: +47 22852608 / +47 22852500,
Fax: +47 22697660, Pb 114 Blindern, N-0314 OSLO, Norway
Jon Haugsand <········@procyon.nr.no> writes:
> However, for large sequences there is unnecessary copying into a new
> variable CHUNK. I would like CHUNK to expand into (SUBSEQ ,PROSEQ ,LOW
> ,HI) within ,@BODY. Is this possible? Other comments on concept and
> code are also welcoming.
You could use SYMBOL-MACROLET.
This has been tested with Allegro/Linux 5.0
(defmacro do-chunk ((chunk sequence step &key (start 0) end) &body body)
(let ((low (gensym))
(high (gensym))
(length (gensym))
(vend (gensym)))
`(let* ((,length (length ,sequence))
(,vend (or ,end ,length)))
(symbol-macrolet ((,chunk (subseq ,sequence ,low ,high)))
(do ((,low ,start ,high)
(,high (min ,length ,step) (min (+ ,high ,step) ,length)))
((>= ,low ,vend) (- ,vend ,start))
,@body)))))
--
Lieven Marchand <···@bewoner.dma.be>
If there are aliens, they play Go. -- Lasker
Jon Haugsand wrote:
>
> I have a macro called DOCHUNK that I use to piece up a sequence in
> order to process smaller pieces. I.e.
>
> (DOCHUNK piece "abcdefgh" 3 (princ piece) (princ " ")))
> abc def gh
I suppose you mean
(DOCHUNK (piece "abcdefgh" 3) (princ piece) (princ " "))
> (defmacro dochunk ((chunk proseq n &key (start 0) end) &body body)
> (let ((low (gensym))
> (hi (gensym))
> (len (gensym))
> (vend (gensym)))
> `(let* ((,len (length ,proseq))
> (,vend (or ,end ,len))
> (,chunk))
> (do ((,low ,start ,hi)
> (,hi (min ,len ,n) (min (+ ,hi ,n) ,len)))
> ((>= ,low ,vend) (- ,vend ,start))
> (setf ,chunk (subseq ,proseq ,low ,hi))
> ,@body))))
>
> However, for large sequences there is unnecessary copying into a new
> variable CHUNK.
Actually, the copying is being done by SUBSEQ, not by the SETF.
The SETF in your macro just copies a pointer (crudely speaking).
So I don't really think there's any "unnecessary copying" going on
(as long as you consider the calls to SUBSEQ to be necessary).
> I would like CHUNK to expand into (SUBSEQ ,PROSEQ ,LOW ,HI) within ,@BODY.
> Is this possible?
If you really wanted to, I suppose you could use SYMBOL-MACROLET. But you
wouldn't avoid any copying that way; in fact, you may even introduce some
extra unnecessary copying. Consider what would happen in code like this:
(DOCHUNK (piece "abcdefghi" 3)
(concatenate 'string piece "=" piece))
With the 'improvement' you have in mind, SUBSEQ would get called 6 times
here, not 3.
--
Arthur Lemmens
In article <···············@procyon.nr.no>,
Jon Haugsand <········@procyon.nr.no> wrote:
>However, for large sequences there is unnecessary copying into a new
>variable CHUNK. I would like CHUNK to expand into (SUBSEQ ,PROSEQ ,LOW
>,HI) within ,@BODY. Is this possible? Other comments on concept and
>code are also welcoming.
SETF doesn't do any copying. Everything in Lisp is references to objects,
there's no copying unless you use a function that explicitly does so.
E.g. if your code contained:
(setf ,chunk (copy-seq (subseq ,proseq ,low ,hi)))
then you would get a copy of the subsequence.
Note that SUBSEQ itself makes a copy; this will happen whether or not you
assign it to a variable or pass it as an argument. So if you make ,CHUNK
expand into that, then every time ,CHUNK appears in @BODY you will get a
*new* subsequence. So what you're doing will result in more copies, not
fewer.
--
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, 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.
In article <···············@procyon.nr.no>, Jon Haugsand
<········@procyon.nr.no> wrote:
> I have a macro called DOCHUNK that I use to piece up a sequence in
> order to process smaller pieces. I.e.
>
> (DOCHUNK piece "abcdefgh" 3 (princ piece) (princ " ")))
> abc def gh
>
> DOCHUNK is defined as follows:
>
> (defmacro dochunk ((chunk proseq n &key (start 0) end) &body body)
> (let ((low (gensym))
> (hi (gensym))
> (len (gensym))
> (vend (gensym)))
> `(let* ((,len (length ,proseq))
> (,vend (or ,end ,len))
> (,chunk))
> (do ((,low ,start ,hi)
> (,hi (min ,len ,n) (min (+ ,hi ,n) ,len)))
> ((>= ,low ,vend) (- ,vend ,start))
> (setf ,chunk (subseq ,proseq ,low ,hi))
> ,@body))))
>
> However, for large sequences there is unnecessary copying into a new
> variable CHUNK. I would like CHUNK to expand into (SUBSEQ ,PROSEQ ,LOW
> ,HI) within ,@BODY. Is this possible? Other comments on concept and
> code are also welcoming.
If you have multiple references then each inlined subseq will make a new
copy, and be even less efficient. You could allocate a single N sized
"chunk" sequenece and move the elements with presumed efficiency, instead
of using SUBSEQ.
If you are using arrays you may be able to use a displaced array and
adjust it as necessary.
Here is a version that does what you asked:
;;; This inlines chunk. It also makes a copy, and possibly many.
;;; P.S. You may want to bind PROSEQ and START to temps.
(defmacro dochunk ((chunk proseq n &key (start 0) end) &body body)
(let ((low (gensym))
(hi (gensym))
(len (gensym))
(vend (gensym)))
`(let* ((,len (length ,proseq))
(,vend (or ,end ,len)))
(do ((,low ,start ,hi)
(,hi (min ,len ,n) (min (+ ,hi ,n) ,len)))
((>= ,low ,vend) (- ,vend ,start))
(symbol-macrolet ((,chunk (subseq ,proseq ,low ,hi)))
,@body)))))
(DOCHUNK (piece "abcdefgh" 3) (princ piece) (princ " "))
abc def gh
This only makes the loop and bindings.
;;; This eliminates chunk and takes variables for its bounds instead.
;;; and a var for the proseq.
;;; P.S. You may want to bind START to a temp.
(defmacro dochunk ((vseq proseq n vcstart vcend &key (start 0) end) &body body)
(let ((len (gensym))
(vend (gensym)))
`(let* ((,vseq ,proseq)
(,len (length ,vseq))
(,vend (or ,end ,len)))
(do ((,vcstart ,start ,vcend)
(,vcend (min ,len ,n) (min (+ ,vcend ,n) ,len)))
((>= ,vcstart ,vend) (- ,vend ,start))
,@body))))
(DOCHUNK
(str "abcdefgh" 3 start end)
(princ (subseq str start end)) (princ " "))
? abc def gh
8
?