Re: [racket-dev] [plt] Push #20898: master branch updated

2010-09-09 Thread Sam Tobin-Hochstadt
On Mon, Aug 23, 2010 at 11:02 AM, Will M. Farr wmf...@gmail.com wrote:
 On Aug 23, 2010, at 7:40 AM, Matthew Flatt wrote:

 Maybe you want to thread the vector index through using `for/fold'
 instead of drawing the index from a sequence. The expansion could
 insert enough `#:when' clauses to compare the index to the length
 before each nested iteration.


 This is exactly what I have decided to do.  New patches attached.  Let me 
 know if you want me to combine them into one.

I've now pushed these patches, with a few minor edits.  Thanks Will!
-- 
sam th
sa...@ccs.neu.edu
_
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/dev


Re: [racket-dev] [plt] Push #20898: master branch updated

2010-08-23 Thread Noel Welsh
On Mon, Aug 23, 2010 at 12:26 AM, Will M. Farr wmf...@gmail.com wrote:
 Thanks for sharing your code, and for the comments.  Let me see if I 
 understand this correctly: the following code should produce a total, a 
 vector whose elements are the partial sums of elements at lower indices than 
 the corresponding element of the input vector, and a vector whose elements 
 are partial sums of elements at the index and lower indices of the input 
 vector, right?

Yes, that's correct.

 1. In my forms, the length is optional, and distinguished (when provided) 
 from the for-clauses by a keyword argument.  In yours, it must be provided as 
 the first for-clause (thus requiring that the index be named).

Yes. Note that my for/vector form will iterate over the indices even
if no other sequence is provided. Thus you can write stuff like this
(taken from some code of mine):

  (for/vector ([i n]) (create-row (+ i l)))

You can ignore the name if you want:

  (for/vector ([_ n-pts]) ...)

 2. In my forms, the final body expression must produce exactly one value, 
 which becomes the vector element.  In yours, the final body expression must 
 produce exactly as many values as the third argument to the length clause (if 
 provided) or 1 (if no third argument is present).

Yes.

 As for difference 1, I think it's nice to be able to avoid providing a length 
 if I don't want to.  Sometimes I may not really care about the efficiency of 
 the loop, but will later need a vector, in which case it's a lot less effort 
 to use (for/vector ((i (in-range 3))) ...) than to have to provide a length.  
 I also prefer the distinguished #:length keyword instead of shoehorning the 
 length argument into a not-really-for-clause.  I'm curious what others think, 
 however.

I like having the index bound to a name if I want it. Otherwise I'm
fine with specifying it in an alternate way.

 Difference #2 seems more significant to me.  I really like the idea of being 
 able to produce multiple vectors simultaneously---as you say, it can have 
 efficiency benefits and also be really convenient.  However, note that the 
 for/list form does not allow multiple values from the last body expression, 
 so there is an argument from consistency to prohibit it in for/vector as well.

We don't have to repeat the mistakes of the past :)

 I'd be open to adding another keyword argument, however, to designate some 
number of vectors (independently of the presence or absence of the #:length 
keyword) for the output.  I'll put that in the next version, and we can see 
what other people think.  As with the #:length argument, I would prefer this 
to be a separate keyword---maybe #:num-vecs, maybe something else---rather 
than trying to fit it into a special for-clause.

Alternatively, it could be a for/vectors / for/fold/vectors form. I'm neutral.

N.
_
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/dev


Re: [racket-dev] [plt] Push #20898: master branch updated

2010-08-23 Thread Matthew Flatt
At Sun, 22 Aug 2010 15:36:03 -0500, Will M. Farr wrote:
  Either choice --- error or stopping --- interacts awkwardly with
  `for*/vector'. If you've going to raise an exception, the natural thing
  to do with `for/vector' would be to stop as soon as the sequence goes
  too far. But `for*/vector' with a length currently just uses
  `for*/vector' without the length; you could check afterward, but that
  would be different than the natural choice for `for/vector'.
  
  Along similar lines, every `for/vector' is a `for*/vector' in a way,
  because a `#:when' clause can introduce a nesting. The `for/vector'
  macro with an without a length behaves very differently than the one
  with a length when a `#:when' clause is used.
  
  Maybe `for/vector' with a length clause should be syntactically
  restricted to have no `#:when' clauses, and maybe there just shouldn't
  be a variant of `for*/vector' that supports `#:length'.
 
 I'll make sure to throw a syntax error if I see a #:when in the for-clauses, 
 and I think I should give up on the for*/vector #:length variant.  I was 
 hoping that you would have some sort of neat trick to keep a running counter 
 during the nested iteration

Maybe you want to thread the vector index through using `for/fold'
instead of drawing the index from a sequence. The expansion could
insert enough `#:when' clauses to compare the index to the length
before each nested iteration.

_
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/dev


Re: [racket-dev] [plt] Push #20898: master branch updated

2010-08-22 Thread Noel Welsh
On Sun, Aug 22, 2010 at 9:36 PM, Will M. Farr wmf...@gmail.com wrote:
 Matthew  co,
...
 I'll make sure to throw a syntax error if I see a #:when in the for-clauses, 
 and I think I should give up on the for*/vector #:length variant.  I was 
 hoping that you would have some sort of neat trick to keep a running counter 
 during the nested iteration

I'm pretty sure this will exclude a lot of my code. I'll have to check tomorrow.

My for/vector allows one to construct multiple vectors in one
iteration. This is fairly useful to efficient code. I also bind the
length to a name. I thought I checked that this counter was exactly
the length after the comprehension terminated, but it appears I don't.
 Code is below.

You won't be surprised to hear I prefer my variant ;-).  I have uses
for every feature that I can dreg up if anyone is interested. I'm keen
to see a for/vector comprehension in Racket.

N.

  (define-syntax (for/fold/vector stx)
(syntax-case stx ()
  [(for/fold/vector
([accum-id init-expr] ...)
([idx length] for-clause ...)
body ...)
   (syntax
(for/fold/vector
 ([accum-id init-expr] ...)
 ([idx length 1] for-clause ...)
 body ...))]

  [(for/fold/vector
([accum-id init-expr] ...)
([idx length n-vectors])
body ...)
   (syntax
(let ([l length])
  (for/fold/vector
   ([accum-id init-expr] ...)
   ([idx l n-vectors] [_ (in-range l)])
   body ...)))]

  [(for/fold/vector
()
([idx length n-vectors] for-clause0 for-clause ...)
body ...)
   (with-syntax ([(v-id ...)
  (datum-syntax
   stx
   (for/list ([i (in-range (syntax-datum (syntax
n-vectors)))])
 (gensym 'for-vector))
   (syntax n-vectors))]
 [(temp-id ...)
  (datum-syntax
   stx
   (for/list ([i (in-range (syntax-datum (syntax
n-vectors)))])
 (gensym 'for-vector))
   (syntax n-vectors))])
 (syntax
  (let* ([l length]
 [idx 0]
 [v-id (make-vector l)] ...)
(begin
  (for (for-clause0 for-clause ...)
   (let-values (([temp-id ...] (let () body ...)))
 (vector-set! v-id idx temp-id) ...
 (set! idx (add1 idx
  (values v-id ...)]

  [(for/fold/vector
([accum-id0 init-expr0] [accum-id init-expr] ...)
([idx length n-vectors] for-clause0 for-clause ...)
body ...)
   (with-syntax ([(v-id ...)
  (datum-syntax
   stx
   (for/list ([i (in-range (syntax-datum (syntax
n-vectors)))])
 (gensym 'for-vector))
   (syntax n-vectors))]
 [(temp-id ...)
  (datum-syntax
   stx
   (for/list ([i (in-range (syntax-datum (syntax
n-vectors)))])
 (gensym 'for-vector))
   (syntax n-vectors))])
 (syntax
  (let* ([l length]
 [idx 0]
 [v-id (make-vector l)] ...)
(let-values (([accum-id0 accum-id ...]
  (for/fold ([accum-id0 init-expr0]
 [accum-id  init-expr] ...)
  (for-clause0 for-clause ...)
(let-values (([accum-id0 accum-id ... temp-id ...]
  (let () body ...)))
  (vector-set! v-id idx temp-id) ...
  (set! idx (add1 idx))
  (values accum-id0 accum-id ...)
  (values accum-id0 accum-id ... v-id ...)]))

  (define-syntax (for/vector stx)
(syntax-case stx ()
  [(for/vector (for-clause ...)
   body ...)
   (syntax (for/fold/vector () (for-clause ...) body ...))]))
_
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/dev


Re: [racket-dev] [plt] Push #20898: master branch updated

2010-08-22 Thread Will M. Farr
Matthew  co,

On Aug 21, 2010, at 7:14 AM, Matthew Flatt wrote:

 I didn't think of this before, but probably you should add a check that
 the length expression proceduces a nonnegative exact integer:
 
 (syntax/loc stx
   (let ((len length-expr))
 (unless (exact-nonnegative-integer? len)
   (raise-type-error 'for/vector exact nonnegative integer len))
 (let ((v (make-vector len)))
   (for ((i (in-naturals))
 for-clause ...)
 (vector-set! v i body))
   v)))

Absolutely.  I'll take care of it.  

 More things that I didn't think of below...
 
 As for the issue 
 of a #:size that doesn't match the length of the iteration, I have been 
 thinking about adding a check inside the loop (for sizes that are too 
 small), 
 and a check outside the loop (for sizes that are too large).  If the size 
 does 
 not match the number of loop iterations would it be better to (error 
 'for/vector loop iterations (~a) and vector size (~a) do not match iter 
 size), raise one of the exn:fail:contract type exceptions, or manually 
 construct a blame object and (raise-blame-error ...), or ...?  If it were 
 simply my code, I would just call (error ...), but that's maybe not the best 
 in a general purpose library.
 
 A `exn:fail:contract' exception would be the right one. It's probably
 easiest to use `raise-mismatch-error'.
 
 It might also be ok to use
 
  (i (in-range 0 len))
 
 and say that the loop stops when either the sequence runs out or the
 number of iterations matches the length. I'd be happy with that but i
 can imagine that others might prefer an error.

I think I prefer this second approach; maybe there is sometimes a use for 
creating a vector that is longer than its initially set length.  For example, I 
could imagine having an extendable vector implementation where you want to 
leave some space at the end for future expansion.

 Either choice --- error or stopping --- interacts awkwardly with
 `for*/vector'. If you've going to raise an exception, the natural thing
 to do with `for/vector' would be to stop as soon as the sequence goes
 too far. But `for*/vector' with a length currently just uses
 `for*/vector' without the length; you could check afterward, but that
 would be different than the natural choice for `for/vector'.
 
 Along similar lines, every `for/vector' is a `for*/vector' in a way,
 because a `#:when' clause can introduce a nesting. The `for/vector'
 macro with an without a length behaves very differently than the one
 with a length when a `#:when' clause is used.
 
 Maybe `for/vector' with a length clause should be syntactically
 restricted to have no `#:when' clauses, and maybe there just shouldn't
 be a variant of `for*/vector' that supports `#:length'.

I'll make sure to throw a syntax error if I see a #:when in the for-clauses, 
and I think I should give up on the for*/vector #:length variant.  I was hoping 
that you would have some sort of neat trick to keep a running counter during 
the nested iteration

I'll send Sam the latest when I'm done with the modifications.

Will
_
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/dev


Re: [racket-dev] [plt] Push #20898: master branch updated

2010-08-21 Thread Matthew Flatt
At Fri, 20 Aug 2010 13:05:12 -0500, Will M. Farr wrote:
 Thanks very much for the comments.  I'll get to work preparing an updated 
 version using #:size soon, and send it to Sam for pushing. 

I should have suggested `#:length', since it corresponds to
`vector-length'.

I didn't think of this before, but probably you should add a check that
the length expression proceduces a nonnegative exact integer:

 (syntax/loc stx
   (let ((len length-expr))
 (unless (exact-nonnegative-integer? len)
   (raise-type-error 'for/vector exact nonnegative integer len))
 (let ((v (make-vector len)))
   (for ((i (in-naturals))
 for-clause ...)
 (vector-set! v i body))
   v)))

More things that I didn't think of below...

 As for the issue 
 of a #:size that doesn't match the length of the iteration, I have been 
 thinking about adding a check inside the loop (for sizes that are too small), 
 and a check outside the loop (for sizes that are too large).  If the size 
 does 
 not match the number of loop iterations would it be better to (error 
 'for/vector loop iterations (~a) and vector size (~a) do not match iter 
 size), raise one of the exn:fail:contract type exceptions, or manually 
 construct a blame object and (raise-blame-error ...), or ...?  If it were 
 simply my code, I would just call (error ...), but that's maybe not the best 
 in a general purpose library.

A `exn:fail:contract' exception would be the right one. It's probably
easiest to use `raise-mismatch-error'.

It might also be ok to use

  (i (in-range 0 len))

and say that the loop stops when either the sequence runs out or the
number of iterations matches the length. I'd be happy with that but i
can imagine that others might prefer an error.


Either choice --- error or stopping --- interacts awkwardly with
`for*/vector'. If you've going to raise an exception, the natural thing
to do with `for/vector' would be to stop as soon as the sequence goes
too far. But `for*/vector' with a length currently just uses
`for*/vector' without the length; you could check afterward, but that
would be different than the natural choice for `for/vector'.

Along similar lines, every `for/vector' is a `for*/vector' in a way,
because a `#:when' clause can introduce a nesting. The `for/vector'
macro with an without a length behaves very differently than the one
with a length when a `#:when' clause is used.

Maybe `for/vector' with a length clause should be syntactically
restricted to have no `#:when' clauses, and maybe there just shouldn't
be a variant of `for*/vector' that supports `#:length'.

_
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/dev


Re: [racket-dev] [plt] Push #20898: master branch updated

2010-08-20 Thread Will M. Farr
Matthew,

Thanks very much for the comments.  I'll get to work preparing an updated 
version using #:size soon, and send it to Sam for pushing.  As for the issue of 
a #:size that doesn't match the length of the iteration, I have been thinking 
about adding a check inside the loop (for sizes that are too small), and a 
check outside the loop (for sizes that are too large).  If the size does not 
match the number of loop iterations would it be better to (error 'for/vector 
loop iterations (~a) and vector size (~a) do not match iter size), raise one 
of the exn:fail:contract type exceptions, or manually construct a blame object 
and (raise-blame-error ...), or ...?  If it were simply my code, I would just 
call (error ...), but that's maybe not the best in a general purpose library.

Will

On Aug 19, 2010, at 5:57 PM, Matthew Flatt wrote:

 At Thu, 19 Aug 2010 18:45:43 -0400, sa...@racket-lang.org wrote:
 +(define-syntax for*/flvector
 +  (lambda (stx)
 +(syntax-case stx ()
 +  ((for*/flvector (for-clause ...) body)
 +   (syntax/loc stx
 + (list-flvector (for*/list (for-clause ...) body
 +  ((for*/flvector length-expr (for-clause ...) body)
 +   (syntax/loc stx
 + (for*/flvector (for-clause ...) body))
 
 
 I'm not comfortable with overloading based on the number of forms (the
 same with `for/vector' and `for*/vector'), since the `for' forms
 normally allow multiple expressions and internal definitions in the
 `for' body.
 
 It would be better to use a `#:size' keyword when supplying a specific
 size instead of relying on the number of forms within `for/vector'.
 
 +...@defform*[((for/vector (for-clause ...) body)
 +   (for/vector length-expr (for-clause ...) body))]
 
 Along the same lines: the `body' meta-variable must always be followed
 by `...+' in a syntax description. If you allow only one expression,
 it's `expr' insteda of `body'. (But I think the solution here is to
 change the syntax so that the docs will have `body ...+'.)
 
 +...@defform*[((for*/vector (for-clause ...) body)
 +   (for*/vector length-expr (for-clause ...) body))])]{
 +
 +Iterates like @scheme[for] or @scheme[for*], but the values of the
 +...@scheme[body] expression are placed in a vector whose length is the
 +number of iterations.  The optional @scheme[length-expr], if present,
 +is evaluated to determine the length of the vector in advance of the
 +iteration; if @scheme[length-expr] is provided, the computation is
 +more efficient.}
 
 The documentation doesn't answer the question that you asked before,
 which is what happens when the result of `length-expr' doesn't match
 the number of iterations. There appear to be no tests for that case,
 either.
 
 _
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/dev

_
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/dev