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:
-
continueof typefn(C) -> !Invoking this continuation re-enters the generator because this causes the current Function Expression to return with a value of type
C. -
breakof 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
}