For Expression
Contents
Syntax
for_expr ::= 'for' param_list in map_expr block_expr
Note that in contrast to most imperative languages like C/C++ or Java, a for
-construct is not a statement but an expression and, thus, yields a value.
Typing
A for
-expression is syntactic sugar for:
f(args, |param_list, continue| -> ! block_expr)
We call f
the generator.
Suppose f
has type:
fn(A, fn(I) -> C) -> B
args
must be of type A
and param_list
of type I
.
Aditionally, Impala implicitly declares two continuations which are usable inside block_expr
:
-
continue
of typefn(C) -> !
Invoking this continuation re-enters the generator because this causes the current Function Expression to return with a value of type
C
. -
break
of typefn(B) -> !
This is the return-continuation of the call to the generator
f
. Thus, invoking this continuation prematurely exits the whole loop. Since the generator’s return type isB
, breaking must also yield something of typeB
.
Since block_expr
also calls the generator again, its type must be C
.
The type of the whole for
expression is B
.
Semantics
Since a for
expression is just syntactic sugar, see Map Expression.
Examples
extern "C" {
fn print_int(i32) -> ();
}
fn range(mut b: i32, e: i32, body: fn(i32) -> ()) -> () {
while b < e {
body(b++)
}
}
fn sum_range(mut b: i32, e: i32, body: fn(i32) -> i32) -> i32 {
let mut sum = 0;
while b < e {
sum += b;
b += body(b)
}
sum
}
fn main(x: i32) -> () {
for i in range(0, 3) {
print_int(i); // 0 1 2
}
let mut step = 1;
let sum = for i in sum_range(0, 16) {
if step == 3 {
step++;
continue(1)
}
print_int(i); // 0 1 4 8 13
step++
};
print_int(sum); // 29
}