;;;; A comparison chain that mixes < with <=, or > with >=, is the and of its ;;;; neighbouring tests, evaluated as a < b < c is. Every operand below comes ;;;; through mark, which prints its tag, so each tag line is a transcript: ;;;; each operand runs exactly once, in source order, even after a false test. once calls = 0 fn mark(tag: str, v: i32) -> i32 calls += 1 print(tag) v fn line(b: bool) -> () print(" -> ") println(b) ; A name is read where it stands, before a call to its right changes it. once level = 0 fn raise() -> i32 level = 10 5 fn dyn-mark(tag, v) print(tag) v fn in-grid(r: i32, rows: i32) -> bool = 0 <= r < rows fn dyn-between(lo, x, hi) = lo <= x < hi fn main() -> i32 print(in-grid(0, 3)) print(" ") print(in-grid(2, 3)) print(" ") print(in-grid(3, 3)) print(" ") print(in-grid(-1, 3)) println("") let a = 1 let b = 2 let c = 2 let d = 5 print(a < b <= c < d) print(" ") print(a < b <= c < 2) print(" ") print(d >= c > 1) print(" ") print(d >= c > 2) println("") ; A middle operand that is a call runs once although two tests name it. line(mark("a", 1) < mark("b", 2) <= mark("c", 2)) line(mark("a", 1) < mark("b", 2) <= mark("c", 1)) ; The first test is false, and every operand still runs. line(mark("a", 3) < mark("b", 2) <= mark("c", 5)) line(mark("a", 1) <= mark("b", 2) < mark("c", 3) <= mark("d", 3)) line(mark("a", 9) >= mark("b", 5) > mark("c", 7) >= mark("d", 0)) println(calls) ; The same over dyn operands. print(dyn-between(0, 0, 3)) print(" ") print(dyn-between(0, 3, 3)) print(" ") print(dyn-between(1.5, 2, 2.5)) println("") line(dyn-mark("p", 1) < dyn-mark("q", 2) <= dyn-mark("r", 2)) line(dyn-mark("p", 5) < dyn-mark("q", 2) <= dyn-mark("r", 9)) print(level < raise() <= 7) level = 0 print(" ") println(<(level, raise(), 7)) 0