Three observations: 

1. The counter-argument to the RnRS quotation would be that for/vector/accum is 
that it expands into a plain old use of the same feature, because "it's just a 
macro." 

2. People designed all kinds of 'loops' in the 70s to find just the right one: 
for/while/repeat/do and all of them with various pre/post/exit/continue/break 
options so that the invariant-wp logicians would be happy (and there is 
something to be said for this). Few of these loops survived because designers 
didn't want them in their languages. 

If you solve the same problem functionally, you often get away with the 
combination of two orthogonal features: tail-calls and accumulators. With that, 
cond and non-recursion in the proper clause. 

3. Pyret's solution is to separate the 'for' from the 'vector' part and I think 
one could also separate the 'accum' part from those two. Then the whole thing 
may read like this: 

 (for vector (accum [t '()] ...)

And to create a similar list structure, you'd write 

 (for list (accum [t '()] ...) 

And then you might ask whether (a) this affects performance and (b) such for 
loops can be abstracted over the second aspect, as in, 

  (lambda (build) (for build (accum [t '()]) ...)


-- Matthias

p.s. I like the elegance of your solution. 







On Mar 11, 2016, at 1:02 PM, 'John Clements' via Racket Users 
<racket-users@googlegroups.com> wrote:

> Often, mutation provides “obvious” ways to do things that may be more 
> difficult to do without it. Here’s one that I came across today: for/vector 
> with an accumulator.
> 
> In this case, I want to create an array of length ’n’ where each cell 
> contains a list of n copies of the symbol ‘zzz. That is, 
> 
> (check-equal? (init-vec 3)
>  ‘#(() (zzz) (zzz zzz) (zzz zzz zzz)))
> 
> … and yes, the vector is of length n+1. No worries.
> 
> The ‘natural’ way to do this is with a helper function that just recomputes a 
> list of ’n’ copies of ‘zzz’. This does actually turn a linear algorithm into 
> an n^2 one, though.
> 
> There’s also a super-easy solution using for/vector with mutation:
> 
> #lang racket
> 
> (require rackunit)
> 
> ;; construct a vector of lists of 'zzzs
> (define (init-vec n)
>  (define t '())
>  (for/vector ([i (in-range (add1 n))])
>    (begin0 t
>            (set! t (cons 'zzz t)))))
> 
> (check-equal? (init-vec 3)
>              '#(() (zzz) (zzz zzz) (zzz zzz zzz)))
> 
> 
> … but the “right” solution sounds like a for/vector with an accumulator, so 
> that I could write:
> 
> ;; construct a vector of lists of 'zzzs
> (define (init-vec n)
>  (for/vector/accum ([t '()]) ([i (in-range (add1 n))])
>    (values t (cons 'zzz t))))
> 
> Honestly, this feels a lot like one of Will Clinger’s “piling feature upon 
> feature” situations, where the problem is that list comprehensions aren’t as 
> flexible as they could be.
> 
> Aaand, naturally, apologies in advance if this feature already exists; about 
> half the time when I ask for a feature in Racket, someone added it last year 
> and I just didn’t notice :).
> 
> Back to your regularly scheduled program,
> 
> John Clements
> 
> P.S.: using for/fold to produce a list and then using list->vector is 
> obviously still linear; I just like the idea of using something like 
> for/vector that doesn’t produce the intermediate list. Seems like it should 
> be possible.
> 
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to