I have the following code working (if you disable typestate) in my half-working
lambdas branch (https://github.com/msullivan/rust/tree/incur-capture):
// I think that this is actually pretty workable as a scheme for using
// blocks to affect control flow. It is a little syntactically heavyweight
// right now, but a lot of that can be fixed. A more lightweight notation
// for blocks will go a long way. The other big problem is the excess of
// closing parens and braces, but that can mostly be fixed with some tweaks
// to the macros that are used to invoke iterators so that we could write
// something like:
// #iter (for_each(v), fn (&T y) -> flow[bool] { ... });
tag flow[T] {
f_normal;
f_break;
f_continue;
f_return(T);
}
// Right now we the parser doesn't allow macros to be defined at top level.
// However, they don't obey scope and so we can just stick them in a
// function and it will work out right...
fn bullshit_hack() {
#macro([#call_body(body),
alt (body) {
f_normal { }
f_break { break; }
f_continue { cont; }
f_return(?x) { ret f_return(x); }
}]);
#macro([#iter(e),
alt (e) {
f_normal { }
f_break | f_continue { fail; }
f_return(?x) { ret x; }
}]);
#macro([#ret(e), {ret f_return(e);}]);
#macro([#cont(e), {ret f_continue;}]);
#macro([#break(e), {ret f_break;}]);
#macro([#body(body), {{body} ret f_normal;}]);
}
fn for_each[T,S](&T[] v, &fn (&T) -> flow[S] f) -> flow[S] {
for (T x in v) {
#call_body (f(x));
}
ret f_normal;
}
fn contains[T](&T[] v, &T x) -> bool {
#iter (for_each(v, fn (&T y) -> flow[bool] { #body({
if (x == y) { #ret (true); }
})}));
ret false;
}
fn map[T,S](&T[] v, &fn (&T) -> S f) -> S[] {
auto w = ~[];
// We don't invoke the #iter macro because we can't force a return.
for_each(v, fn (&T x) -> flow[()] { #body({
w += ~[f(x)];
})});
ret w;
}
fn log_int_vec(&int[] v) {
for_each(v, fn (&int i) -> flow[()] { #body({
log_err i;
})});
}
fn main() {
auto v = ~[1,2,3,4,5,6,7];
assert(contains(v, 7) == true);
assert(contains(v, 2) == true);
assert(contains(v, 0) == false);
auto w = map(v, fn(&int i) -> int { ret i*i; });
assert(contains(w, 36) == true);
assert(contains(w, 5) == false);
log_int_vec(w);
}
----- Original Message -----
> Made a mistake with #iter. It should be:
> alt (e) {
> f_normal { }
> f_break | f_continue { fail; }
> f_return(?x) { return x; }
> }
>
> ----- Original Message -----
> > There are approximately 549839483286534 interrelated sub-issues
> > currently complicating figuring out how we want to treat
> > functions/closures/blocks.
> >
> > Patrick, Graydon, and I spent some time yesterday tackling the
> > sub-issue of dealing with blocks that can affect control flow, for
> > use
> > in iterator functions.
> >
> > Originally the plan was that all lambda-blocks could trigger
> > break/continue. The downside of this is that it means we need to
> > support a block causing a break or continue whenever we call one. It
> > also means that blocks would have a different calling convention, so
> > to pass a "normal" function to something that can also take a block,
> > it needs to be converted. Furthermore, there are a lot of places
> > that
> > should be able to take blocks where it doesn't really make sense to
> > break and continue (map, for instance: what does map return if the
> > block returns early?).
> >
> > The proposal we discussed looked something like:
> > Make the flow-controlling return value of an iterator-body-block
> > explicit by introducing a new type "flow_control" that represents
> > the
> > flow-controlling implicit return value of the iterator-body-block.
> > Then, the type of a vec_for_each function would be something like
> > "fn[T](&fn(&T) -> flow_control, &T[])".
> > And then we require that you can call only a function that returns
> > flow_control from within a loop. (We could also reify flow_control
> > even more, so that you can actually get and create and inspect
> > flow_control values, and then have some explicit operation to apply
> > the result of a flow_control value.)
> >
> > A little trickier is if we want to allow a iterator-body-block to
> > force a return of the function that called the iterator. This is
> > useful but a little terrifying. It requires that the flow_control
> > value be passed through the iterator function and then interpreted
> > by
> > the calling function. If we want to be able to force the return of
> > some value, then we would probably need to make flow_control
> > parameterized, giving flow_control[T]. Furthermore, you want the
> > iterator function to propagate the return flow_control but you just
> > want the calling function to return without forcing /its/ caller to
> > return... You could do something where you inspect the return types
> > of
> > the function and use that to figure out what to do, but. I think
> > trying to do that while keeping handling of the flow_control value
> > completely implicit gets pretty hairy pretty fast.
> >
> > Also note that one downside of making explicit the flow_control type
> > is that you can no longer directly pass
> >
> > ----------------------------------------------------------------
> > I have an extension to that scheme that I think fixes up some of
> > these
> > issues. My idea is to take the idea of reifying flow_control to its
> > extreme, getting rid of most of the special cases.
> >
> > We could make flow_control an ordinary tag type and then have
> > convenience macros that return the tags as well as a macro that
> > interprets a flow_control value and applies it. (All of the things I
> > say are macros could also just be language features.)
> >
> > so we could do something like:
> > tag flow_control[T] {
> > f_normal;
> > f_break;
> > f_continue;
> > f_return(T);
> > }
> >
> > And then we have some simple macros to return the different
> > flow_control values, so that #return means "ret f_return" (or don't
> > bother and do it explicitly).
> >
> > The actual control flow would be handled by some macros (I'm not
> > sure
> > what our macro syntax will be like, so I'm making things up):
> > The #call_body macro, which is for calling the body of an iterator.
> > "#call_body e" would expand to:
> > alt (e) {
> > f_normal { }
> > f_break { break; }
> > f_continue { continue; }
> > f_return(?x) { return f_return(x); } // propagate the return to the
> > caller
> > }
> > And the #iter macro, which is for calling an iterator function if
> > you
> > want to allow the block to trigger a return. "#iter e" would expand
> > to:
> > alt (e) {
> > f_normal { }
> > f_break { break; }
> > f_continue { continue; }
> > f_return(?x) { return x; }
> > }
> >
> > A full example of this scheme in action:
> > fn for_each[T,S](&T[] v, &fn(&T) -> flow_control[S] f) ->
> > flow_control[S] {
> > for each (x in v) {
> > #call_body f(x);
> > }
> > ret f_normal;
> > }
> >
> > fn contains[T](&T[] v, &T x) -> bool {
> > #iter for_each(v, {|y|
> > if (x == y) { #return true; }
> > ret f_normal;
> > });
> > ret false;
> > }
> >
> > I think this is mostly very clean and unburdensome, except for the
> > "ret f_normal"s that are required at the end of all bodies, which is
> > an enormous burden. I have two possibilities to solve that:
> > 1) The "more principled" solution is to introduce a macro #body such
> > that #body {|x1|...|xn| code} becomes {|x1|...|xn| { code } ret
> > f_normal;}. contains then becomes:
> > fn contains[T](&T[] v, &T x) -> bool {
> > #iter for_each(v, #body {|y|
> > if (x == y) { #return true; }
> > });
> > ret false;
> > }
> >
> > 2) Alternately, we could make it so that there is an implicit "ret
> > f_normal" at the end of every function that returns flow_control, in
> > the same way that (notionally) there is an implicit "ret ()" at the
> > end of every function that returns ().
> >
> > I like this solution because I think it effectively captures a
> > really
> > handy use of blocks without needing add much "magic" or special
> > cases.
> > In particular, I think that making it explicit gives us a good
> > method
> > for forcing the return of a value from an iterator body block
> > whereas
> > I don't think we had a good way to do that when keeping the control
> > flow handling implicit. It also has the advantage that the
> > flow_control value can be inspected and handled in custom ways
> > (perhaps there is some cleanup that needs to be done before
> > returning).
> >
> > ------------------------------------------------------------------
> >
> > What are people's thoughts?
> >
> > -sully
> > _______________________________________________
> > Rust-dev mailing list
> > [email protected]
> > https://mail.mozilla.org/listinfo/rust-dev
> _______________________________________________
> Rust-dev mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/rust-dev
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev