Using the Iterate libraryHel

Discussion of Common Lisp
Post Reply
Harnon
Posts: 78
Joined: Wed Jul 30, 2008 9:59 am

Using the Iterate libraryHel

Post by Harnon » Wed Sep 16, 2009 6:12 am

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")))
          )))

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Using the Iterate libraryHel

Post by ramarren » Wed Sep 16, 2009 8:43 am

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.

Harnon
Posts: 78
Joined: Wed Jul 30, 2008 9:59 am

Re: Using the Iterate libraryHel

Post by Harnon » Wed Sep 16, 2009 10:55 am

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.

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Using the Iterate libraryHel

Post by ramarren » Wed Sep 16, 2009 11:33 am

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.

Harnon
Posts: 78
Joined: Wed Jul 30, 2008 9:59 am

Re: Using the Iterate libraryHel

Post by Harnon » Wed Sep 16, 2009 1:30 pm

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.

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Using the Iterate libraryHel

Post by ramarren » Wed Sep 16, 2009 1:49 pm

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.

Post Reply