Page 1 of 1
Using the Iterate libraryHel
Posted: Wed Sep 16, 2009 6:12 am
by Harnon
Hello! I'm trying ot use the iteate library to define a collector which concatenates into a string. Howveer, i cannot find a way for it to automatically return
its result if there are no other collecting vars.
for example,
(iter (for arg in '(a b)) (collecting arg)) will automatically return '(a b)
I would like
(iter (for arg in-vector "HI") (joining arg)) to auto return "HI"
Is there something available for this or must i start hacking? Notice that joining joins arbitrary symbols, chars, and string which is not
available currently in iterate as an accumulating clause ( i think...) Also its alwways a string inside iterate, unlike the other clauses which can be coerced to
a different result but are not that way inside the iter loop.
Code: Select all
(defmacro-clause (JOINING str &optional INTO result-var AT (place 'end))
(let ((pl (string place)))
`(for ,result-var
= ,(cond
((equalp pl "end")
`(strcat ,result-var ,str)
)
((equalp pl "start")
`(strcat ,str ,result-var))
(t (error "AT in JOINING must be either start or end")))
)))
Re: Using the Iterate libraryHel
Posted: Wed Sep 16, 2009 8:43 am
by ramarren
I think something like this will do what you want:
Code: Select all
(defmacro-clause (JOINING str &optional INTO result-var AT (place 'end))
(let ((x (gensym))
(y (gensym)))
(cond ((string-equal place "END")
`(reducing ,str by #'(lambda (,x ,y)
(concatenate 'string ,x (string ,y)))
initial-value "" into ,result-var))
((string-equal place "START")
`(reducing ,str by #'(lambda (,x ,y)
(concatenate 'string (string ,y) ,x))
initial-value ""
into ,result-var))
(t (error "AT in JOINING must be either start or end")))))
Note that this is quite inefficient, as it constructs an intermediary string at every iteration, but if it is a requirement then this will work. If it is not, the using a string-output-stream would likely be better, but would allow only adding to an end. Gathering into a list and converting to a string at the end is usually a better solution for these kind of things.
Re: Using the Iterate libraryHel
Posted: Wed Sep 16, 2009 10:55 am
by Harnon
I actually wouldn't mind cummulating it into a list and then coercing it at end . Im not referring to the string inside the loop after all. I just want it to be succinct.
Re: Using the Iterate libraryHel
Posted: Wed Sep 16, 2009 11:33 am
by ramarren
Harnon wrote:I actually wouldn't mind cummulating it into a list and then coercing it at end . Im not referring to the string inside the loop after all. I just want it to be succinct.
In that case I think something like:
Code: Select all
(defmacro-clause (JOINING str &optional INTO result-var AT (place 'end))
(let ((result-var (or result-var iterate::*result-var*))
(string-stream (gensym "STRING-STREAM"))
(element (gensym "ELEMENT")))
(let ((result-code (cond ((string-equal place "END")
result-var)
((string-equal place "START")
`(reverse ,result-var))
(t (error "AT in JOINING must be either start or end")))))
`(progn
(collect ,str into ,result-var)
(finally
(setf ,result-var
(with-output-to-string (,string-stream)
(dolist (,element ,result-code)
(write-sequence (string ,element) ,string-stream)))))))))
would be faster and seems to work. It uses the internal symbol iterate::*result-var*, but it is mentioned in documentation, at the end of
this page and
here. It says that you are not supposed to change it, but I don't think it is going to break something to do it from epilogue.
Re: Using the Iterate libraryHel
Posted: Wed Sep 16, 2009 1:30 pm
by Harnon
So, using that var, i redefined mine as follows
Code: Select all
(defmacro-clause (JOINING str &optional INTO result-var AT (place 'end))
(let ((pl (string place))
(^result-var (or result-var iterate::*result-var*)))
`(progn
(with ,^result-var = "")
(setq ,^result-var
,(cond
((equalp pl "end")
`(strcat ,^result-var ,str))
((equalp pl "start")
`(strcat ,str ,^result-var))
(t (error "AT in JOINING must be either start or end")))))))
The only problem i can see is if you want to do multiple things collecting into default reutrn value like
(iter (for item in-vector "HI") (joining item) (joining "H"))
This will return an error because you can't bind multiple withs with the same name. Interestingly, (collecting item) (collecting "H") works fine.
I wander how this could be achieved with user defined iterate constructs.
Re: Using the Iterate libraryHel
Posted: Wed Sep 16, 2009 1:49 pm
by ramarren
Harnon wrote:I wander how this could be achieved with user defined iterate constructs.
Most such constructs can and probably should be expressed in terms of standard iterate clauses, as I did. Looking at the code, standard clauses are implemented in a rather complex way integrating them into the iterate system, and there is no reason for replicating that.