Re: [racket-dev] for loops with interleaved escape continuations

2014-07-02 Thread Matthias Felleisen

On Jul 2, 2014, at 2:26 PM, Neil Van Dyke wrote:

> Loop syntax and sugar is fine.  And having "#:continue" and "#:break" 
> keywords at the top of the form is sufficient warning of surprises ahead, 
> IMHO.
> 
> I do have a minor ongoing concern that people coming from other languages 
> lately latch onto the "for" family of forms from the start, don't get enough 
> exposure to named-"let", and/or mutually/self-recursive procedures, and then 
> end up shoehorning problems into the "for" forms (with flag variables and 
> redundant checks and such).  "break" and "continue" can be good shoehorns.
> 
> I still half-seriously like the idea of having unlockable language feature 
> achievements, like unlockable equipment in video games.  I might play with 
> that idea soon.

Cute idea. It generalizes the teaching languages, which at some point we wanted 
to explore, too. We dubbed this HLI as in Human-Language Interface. -- Matthias


_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] for loops with interleaved escape continuations

2014-07-02 Thread Neil Van Dyke
Loop syntax and sugar is fine.  And having "#:continue" and "#:break" 
keywords at the top of the form is sufficient warning of surprises 
ahead, IMHO.


I do have a minor ongoing concern that people coming from other 
languages lately latch onto the "for" family of forms from the start, 
don't get enough exposure to named-"let", and/or mutually/self-recursive 
procedures, and then end up shoehorning problems into the "for" forms 
(with flag variables and redundant checks and such).  "break" and 
"continue" can be good shoehorns.


I still half-seriously like the idea of having unlockable language 
feature achievements, like unlockable equipment in video games.  I might 
play with that idea soon.


Neil V.

<>_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] for loops with interleaved escape continuations

2014-07-02 Thread Matthias Felleisen

Interestingly enough, I tried to explain this idea to the Imperative Advanced 
Placement crowd in the 1990s. With functional programming -- control from 
tail-recursive functions -- is more expressive than programming with limited 
loops because you can (1) break/resume/continue/foobar your 'loops' more easily 
(including loops that communicate actual values instead of void) and (2) you 
can write abstractions over these things once you have good use cases. 

Now we're in a position to do so and what John & Sam sketch out is finally a 
realization of this idea. 

-- Matthias


_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] for loops with interleaved escape continuations

2014-07-01 Thread Sam Tobin-Hochstadt
On Wed, Jul 2, 2014 at 12:52 AM, John Clements
 wrote:
>
> On Jul 1, 2014, at 3:46 PM, Sam Tobin-Hochstadt  wrote:
>
>> I disagree strongly that this is un-rackety. Consider the following loop:
>>
>> (define v )
>> (let loop ([i 100])
>> (define e (vector-ref v i))
>> (cond [(zero? i) null]
>>   [(= 999 e) null]
>>   [(even? e) (loop (add1 i))]
>>   [else (cons e (loop add1 i))]))
>>
>> I don't think that's un-Rackety.
>>
>> Here's that loop with break/continue:
>>
>> (for/list ([i (in-range 100 0 -1)])
>>  (define e (vector-ref v i))
>>  (cond [(= 999 e) (break)]
>>   [(even? e) (continue)]
>>   [else e]))
>
> You don’t like the non-capturing alternative
>
> (for/list ([i (in-range 100 0 -1)]
>#:continue continue
>#:break break)
>  (define e (vector-ref v i))
>  (cond [(= 999 e) (break)]
>   [(even? e) (continue)]
>   [else e]))
>
> ?

Sorry, I meant to write the hygenic version that you provide.

Sam

>
> Sorry, I’m working on implementing hygiene for Rust right now, and I’m kind 
> of knee-jerk in favor of non-capturing….
>
> John
>
>>
>> I don't think that's un-Rackety either.
>>
>> Sam
>>
>> On Tue, Jul 1, 2014 at 10:59 PM, Neil Van Dyke  wrote:
>>> If adding break&continue features to your fancy iteration syntax, I propose
>>> that any uses of these features in source code be somehow very prominent.
>>>
>>> For example, perhaps there is a keyword that must be at the top of the fancy
>>> iteration form, something like
>>> "#:enable-continue-here-because-programmer-cannot-be-bothered-to-write-this-in-idiomatic-racket".
>>>
>>> This prominence warns readers of the code to be on the lookout for surprise
>>> control flow (like they would on the rare occasion that they saw a "call/ec"
>>> around a loop).  It also hints to newbie programmers that they are
>>> discouraged from simply transliterating syntax from other languages (rather
>>> than learning better control flow and structuring techniques).
>>>
>>> Neil V.
>>>
>>>
>>> _
>>>  Racket Developers list:
>>>  http://lists.racket-lang.org/dev
>>>
>> _
>>  Racket Developers list:
>>  http://lists.racket-lang.org/dev
>

_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] for loops with interleaved escape continuations

2014-07-01 Thread John Clements

On Jul 1, 2014, at 3:46 PM, Sam Tobin-Hochstadt  wrote:

> I disagree strongly that this is un-rackety. Consider the following loop:
> 
> (define v )
> (let loop ([i 100])
> (define e (vector-ref v i))
> (cond [(zero? i) null]
>   [(= 999 e) null]
>   [(even? e) (loop (add1 i))]
>   [else (cons e (loop add1 i))]))
> 
> I don't think that's un-Rackety.
> 
> Here's that loop with break/continue:
> 
> (for/list ([i (in-range 100 0 -1)])
>  (define e (vector-ref v i))
>  (cond [(= 999 e) (break)]
>   [(even? e) (continue)]
>   [else e]))

You don’t like the non-capturing alternative

(for/list ([i (in-range 100 0 -1)]
   #:continue continue
   #:break break)
 (define e (vector-ref v i))
 (cond [(= 999 e) (break)]
  [(even? e) (continue)]
  [else e]))

?

Sorry, I’m working on implementing hygiene for Rust right now, and I’m kind of 
knee-jerk in favor of non-capturing….

John

> 
> I don't think that's un-Rackety either.
> 
> Sam
> 
> On Tue, Jul 1, 2014 at 10:59 PM, Neil Van Dyke  wrote:
>> If adding break&continue features to your fancy iteration syntax, I propose
>> that any uses of these features in source code be somehow very prominent.
>> 
>> For example, perhaps there is a keyword that must be at the top of the fancy
>> iteration form, something like
>> "#:enable-continue-here-because-programmer-cannot-be-bothered-to-write-this-in-idiomatic-racket".
>> 
>> This prominence warns readers of the code to be on the lookout for surprise
>> control flow (like they would on the rare occasion that they saw a "call/ec"
>> around a loop).  It also hints to newbie programmers that they are
>> discouraged from simply transliterating syntax from other languages (rather
>> than learning better control flow and structuring techniques).
>> 
>> Neil V.
>> 
>> 
>> _
>>  Racket Developers list:
>>  http://lists.racket-lang.org/dev
>> 
> _
>  Racket Developers list:
>  http://lists.racket-lang.org/dev


_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] for loops with interleaved escape continuations

2014-07-01 Thread Sam Tobin-Hochstadt
I disagree strongly that this is un-rackety. Consider the following loop:

(define v )
(let loop ([i 100])
 (define e (vector-ref v i))
 (cond [(zero? i) null]
   [(= 999 e) null]
   [(even? e) (loop (add1 i))]
   [else (cons e (loop add1 i))]))

I don't think that's un-Rackety.

Here's that loop with break/continue:

(for/list ([i (in-range 100 0 -1)])
  (define e (vector-ref v i))
  (cond [(= 999 e) (break)]
   [(even? e) (continue)]
   [else e]))

I don't think that's un-Rackety either.

Sam

On Tue, Jul 1, 2014 at 10:59 PM, Neil Van Dyke  wrote:
> If adding break&continue features to your fancy iteration syntax, I propose
> that any uses of these features in source code be somehow very prominent.
>
> For example, perhaps there is a keyword that must be at the top of the fancy
> iteration form, something like
> "#:enable-continue-here-because-programmer-cannot-be-bothered-to-write-this-in-idiomatic-racket".
>
> This prominence warns readers of the code to be on the lookout for surprise
> control flow (like they would on the rare occasion that they saw a "call/ec"
> around a loop).  It also hints to newbie programmers that they are
> discouraged from simply transliterating syntax from other languages (rather
> than learning better control flow and structuring techniques).
>
> Neil V.
>
>
> _
>   Racket Developers list:
>   http://lists.racket-lang.org/dev
>
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] for loops with interleaved escape continuations

2014-07-01 Thread Neil Van Dyke
If adding break&continue features to your fancy iteration syntax, I 
propose that any uses of these features in source code be somehow very 
prominent.


For example, perhaps there is a keyword that must be at the top of the 
fancy iteration form, something like 
"#:enable-continue-here-because-programmer-cannot-be-bothered-to-write-this-in-idiomatic-racket".


This prominence warns readers of the code to be on the lookout for 
surprise control flow (like they would on the rare occasion that they 
saw a "call/ec" around a loop).  It also hints to newbie programmers 
that they are discouraged from simply transliterating syntax from other 
languages (rather than learning better control flow and structuring 
techniques).


Neil V.

<>_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] for loops with interleaved escape continuations

2014-07-01 Thread Sam Tobin-Hochstadt
I think this is a good idea, and something that I've wanted for a long
time. But there are ways to make it much better, and generalize to all
loops.

First, recognize that a `for/...` loop is really a recursive function,
which is passing along a bunch of arguments. In this setting,
`continue` means to make a new recursive call with the same arguments
as last time, and `break` means to exit the loop with the current
values of the arguments.

One solution, therefore, is to just bind `break` and `continue`
identifiers as specified to functions that just make these calls. This
works perfectly if you call break/continue in tail position with
respect to the loop body, but does weird things otherwise.

Another solution is to bind break and continue to function which use
let/ec to jump out of whatever context they're in inside the loop
body, and then make the appropriate transition to the next
iteration/the end of the loop.

A third solution is to have explicit keywords that can appear in the
loop body, such as #:break and #:continue, and which are transformed
to make the appropriate recursive call. This avoids both the
continuation capture and the potential strange behavior when called in
non-tail position.

A fourth solution, not currently implementable, would be to take
solution 1, plus a way of statically erroring when certain expressions
didn't appear in tail position wrt another expression.

I think 4 would be my preference, but of the other three I'm unsure.

Sam

On Fri, Jun 27, 2014 at 11:15 PM, Jay Kominek  wrote:
> I've been converting a bunch of Python to Racket lately, and I have a
> lot of loops that use break and continue. I end up turning them into:
>
> (let/ec break
>   (for (...)
> (let/ec continue
>   ; do some work
>   (when this-iteration-isn't-what-i-want
> (continue))
>   ; do more expensive work
>   (when found-what-i-want
> (break what-i-want)
>
> I thought it would be nice if the let/ec's could be integrated with
> for, so that you could instead write:
>
> (for (#:ec break
>...
>#:ec continue)
>   ; ...same as above...
>
> In an attempt to help convey the behavior I want, I threw this patch together:
>
> https://github.com/jkominek/racket/commit/b291a0b994c679445b3210bd3efba8c6cea867e4
>
> I feel it behaves reasonably when using for and for/fold, but for/list
> doesn't behave in any way I'd hope for.
>
> Ideally somebody who understands for's implementation will agree that
> this is a great idea, and go make it all work nicely. :) Failing that
> I'm open to suggestions for how to make it behave better, in a fashion
> which would make it appropriate for inclusion.
>
> --
> Jay Kominek
> _
>   Racket Developers list:
>   http://lists.racket-lang.org/dev
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] for loops with interleaved escape continuations

2014-07-01 Thread Matthias Felleisen

In principle I like this #:ec idea, but I would feel more comfortable if you 
explored the whole range of for loops and their interactions with this new 
feature. -- Matthias







On Jun 28, 2014, at 6:54 AM, Jay Kominek wrote:

> On Fri, Jun 27, 2014 at 8:40 PM, J. Ian Johnson  wrote:
>> One is that #:when in for-clauses allows you to skip iterations, but you 
>> want it in the body. This is a cosmetic difference that you can get around 
>> by doing #:when (begin imperative-stuff-before-guard guard). If you want ecs 
>> to escape an entire for loop, that's what #:break is for. If you want ecs to 
>> escape even more for loops, well, that is an unplanned but a possibly useful 
>> feature for nested for loops.
> 
> Yes, #:when gets frustratingly close, but if
> imperative-stuff-before-guard does something expensive (fetches the
> ith web page, or what have you), I've got to repeat it in the body if
> I actually want to use the value. Same issue with #:break and all the
> other guards.
> 
> If I end up wanting #:when, #:break, and the body of the expression to
> all make use of some expensive value, I'm stuck reproducing it. (Or
> setting up some previous loop to make a bunch of promises that I can
> force... bleh.)
> 
> Would I have more luck selling folks on some sort of #:let [id
> val-expr] construct that could mix in with the sequences? That'd get
> me most of what I was going for, and it is probably(?) a lot more
> obvious how it should behave.
> 
>> The other is that this is not Rackety and thus not natively supported for 
>> the same reason there are no "return" statements. The for macros are so much 
>> more than Python's for - they can produce values. Don't throw everything 
>> into the void :)
> 
> Sorry, I should've put more than a moment's effort into my example. I
> specifically tried to ensure that this can do more than Python's break
> & continue! In fact, this allows poor boring "for" who normally
> produces nothing but void to produce a useful value. Here are some
> more examples, again contrived because I'm trying to keep them short,
> but hopefully making more apparent the advantage over simple break &
> continue:
> 
> (for (#:ec break
>  [x (in-range 0 10)])
>  (when(= x 2)
>(break "found it!"))
>  (printf "~a~n" x))
> 
> 0
> 1
> "found it!"
> 
> 
> (for/fold ([x 0] [y 0])
>  (#:ec break
>   [i (in-range0 10)]
>   #:eccontinue)
>  (when (= i 3)
>(continue (+ x 1000) (+ y 1000)))
>  (when(= i 7)
>(break (exact->inexact x) y))
>  (values (add1 x) (add1 y)))
> 
> 1006.0
> 1006
> 
> The inner escape continuation passes its values along to the next
> iteration, while the outer one can return values for the entire
> expression. And of course, it can be interleaved between sequences,
> just like #:when and friends.
> 
> I was allowing the use of the continuations without arguments so that
> there'd be a more obvious translation from languages with wimpy
> control statements, but they raise the issue of what values should be
> used by default.
> 
> (And to reiterate the current inadequacies, it doesn't behave at all
> properly with for/list, for/vector or for/set.)
> 
> Thanks for looking.
> 
> -- 
> Jay Kominek
> 
> _
>  Racket Developers list:
>  http://lists.racket-lang.org/dev


_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] for loops with interleaved escape continuations

2014-06-27 Thread Danny Yoo
Hi Jay,

Have not been following Racket development too closely lately, but
perhaps you might find this helpful?

http://planet.racket-lang.org/display.ss?package=while-loop.plt&owner=dyoo
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] for loops with interleaved escape continuations

2014-06-27 Thread Jay Kominek
On Fri, Jun 27, 2014 at 8:40 PM, J. Ian Johnson  wrote:
> One is that #:when in for-clauses allows you to skip iterations, but you want 
> it in the body. This is a cosmetic difference that you can get around by 
> doing #:when (begin imperative-stuff-before-guard guard). If you want ecs to 
> escape an entire for loop, that's what #:break is for. If you want ecs to 
> escape even more for loops, well, that is an unplanned but a possibly useful 
> feature for nested for loops.

Yes, #:when gets frustratingly close, but if
imperative-stuff-before-guard does something expensive (fetches the
ith web page, or what have you), I've got to repeat it in the body if
I actually want to use the value. Same issue with #:break and all the
other guards.

If I end up wanting #:when, #:break, and the body of the expression to
all make use of some expensive value, I'm stuck reproducing it. (Or
setting up some previous loop to make a bunch of promises that I can
force... bleh.)

Would I have more luck selling folks on some sort of #:let [id
val-expr] construct that could mix in with the sequences? That'd get
me most of what I was going for, and it is probably(?) a lot more
obvious how it should behave.

> The other is that this is not Rackety and thus not natively supported for the 
> same reason there are no "return" statements. The for macros are so much more 
> than Python's for - they can produce values. Don't throw everything into the 
> void :)

Sorry, I should've put more than a moment's effort into my example. I
specifically tried to ensure that this can do more than Python's break
& continue! In fact, this allows poor boring "for" who normally
produces nothing but void to produce a useful value. Here are some
more examples, again contrived because I'm trying to keep them short,
but hopefully making more apparent the advantage over simple break &
continue:

(for (#:ec break
  [x (in-range 0 10)])
  (when(= x 2)
(break "found it!"))
  (printf "~a~n" x))

0
1
"found it!"


(for/fold ([x 0] [y 0])
  (#:ec break
   [i (in-range0 10)]
   #:eccontinue)
  (when (= i 3)
(continue (+ x 1000) (+ y 1000)))
  (when(= i 7)
(break (exact->inexact x) y))
  (values (add1 x) (add1 y)))

1006.0
1006

The inner escape continuation passes its values along to the next
iteration, while the outer one can return values for the entire
expression. And of course, it can be interleaved between sequences,
just like #:when and friends.

I was allowing the use of the continuations without arguments so that
there'd be a more obvious translation from languages with wimpy
control statements, but they raise the issue of what values should be
used by default.

(And to reiterate the current inadequacies, it doesn't behave at all
properly with for/list, for/vector or for/set.)

Thanks for looking.

-- 
Jay Kominek

_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] for loops with interleaved escape continuations

2014-06-27 Thread J. Ian Johnson
There are a couple issues here,
One is that #:when in for-clauses allows you to skip iterations, but you want 
it in the body. This is a cosmetic difference that you can get around by doing 
#:when (begin imperative-stuff-before-guard guard). If you want ecs to escape 
an entire for loop, that's what #:break is for. If you want ecs to escape even 
more for loops, well, that is an unplanned but a possibly useful feature for 
nested for loops.
The other is that this is not Rackety and thus not natively supported for the 
same reason there are no "return" statements. The for macros are so much more 
than Python's for - they can produce values. Don't throw everything into the 
void :)
-Ian
 Original Message -
From: Jay Kominek 
To: dev 
Sent: Fri, 27 Jun 2014 17:15:45 -0400 (EDT)
Subject: [racket-dev] for loops with interleaved escape continuations

I've been converting a bunch of Python to Racket lately, and I have a
lot of loops that use break and continue. I end up turning them into:

(let/ec break
  (for (...)
(let/ec continue
  ; do some work
  (when this-iteration-isn't-what-i-want
(continue))
  ; do more expensive work
  (when found-what-i-want
(break what-i-want)

I thought it would be nice if the let/ec's could be integrated with
for, so that you could instead write:

(for (#:ec break
   ...
   #:ec continue)
  ; ...same as above...

In an attempt to help convey the behavior I want, I threw this patch together:

https://github.com/jkominek/racket/commit/b291a0b994c679445b3210bd3efba8c6cea867e4

I feel it behaves reasonably when using for and for/fold, but for/list
doesn't behave in any way I'd hope for.

Ideally somebody who understands for's implementation will agree that
this is a great idea, and go make it all work nicely. :) Failing that
I'm open to suggestions for how to make it behave better, in a fashion
which would make it appropriate for inclusion.

-- 
Jay Kominek
_
  Racket Developers list:
  http://lists.racket-lang.org/dev

_
  Racket Developers list:
  http://lists.racket-lang.org/dev


[racket-dev] for loops with interleaved escape continuations

2014-06-27 Thread Jay Kominek
I've been converting a bunch of Python to Racket lately, and I have a
lot of loops that use break and continue. I end up turning them into:

(let/ec break
  (for (...)
(let/ec continue
  ; do some work
  (when this-iteration-isn't-what-i-want
(continue))
  ; do more expensive work
  (when found-what-i-want
(break what-i-want)

I thought it would be nice if the let/ec's could be integrated with
for, so that you could instead write:

(for (#:ec break
   ...
   #:ec continue)
  ; ...same as above...

In an attempt to help convey the behavior I want, I threw this patch together:

https://github.com/jkominek/racket/commit/b291a0b994c679445b3210bd3efba8c6cea867e4

I feel it behaves reasonably when using for and for/fold, but for/list
doesn't behave in any way I'd hope for.

Ideally somebody who understands for's implementation will agree that
this is a great idea, and go make it all work nicely. :) Failing that
I'm open to suggestions for how to make it behave better, in a fashion
which would make it appropriate for inclusion.

-- 
Jay Kominek
_
  Racket Developers list:
  http://lists.racket-lang.org/dev