A loop's initialisers are checked in order and each sees the names bound before it, as a let's do
This commit is contained in:
parent
3a3674efb7
commit
b4e19bebf8
11
lib/check.ml
11
lib/check.ml
@ -4737,8 +4737,10 @@ and check_dotimes ctx ~want loc label name (b : Ast.bounds) body =
|
|||||||
and check_loop ctx ?want loc bs body =
|
and check_loop ctx ?want loc bs body =
|
||||||
scoped ctx (fun () ->
|
scoped ctx (fun () ->
|
||||||
(* Each initial value is evaluated once, before the loop, exactly as a
|
(* Each initial value is evaluated once, before the loop, exactly as a
|
||||||
[let]'s is and as [dotimes]'s bound is. *)
|
[let]'s is and as [dotimes]'s bound is — and bound before the next is
|
||||||
let inits =
|
checked, as a [let]'s is, so a later initialiser sees an earlier
|
||||||
|
name. *)
|
||||||
|
let binds =
|
||||||
map_lr
|
map_lr
|
||||||
(fun (n, v) ->
|
(fun (n, v) ->
|
||||||
let v = check ctx v in
|
let v = check ctx v in
|
||||||
@ -4747,12 +4749,9 @@ and check_loop ctx ?want loc bs body =
|
|||||||
fail v.Tast.loc "%s would be bound to %s, which is not a value" n
|
fail v.Tast.loc "%s would be bound to %s, which is not a value" n
|
||||||
(Types.to_string v.Tast.ty)
|
(Types.to_string v.Tast.ty)
|
||||||
| _ -> ());
|
| _ -> ());
|
||||||
(n, v))
|
(bind ctx n v.Tast.ty ~assignable:true, v))
|
||||||
bs
|
bs
|
||||||
in
|
in
|
||||||
let binds =
|
|
||||||
List.map (fun (n, v) -> (bind ctx n v.Tast.ty ~assignable:true, v)) inits
|
|
||||||
in
|
|
||||||
let names = List.map (fun (slot, v) -> (slot, v.Tast.ty)) binds in
|
let names = List.map (fun (slot, v) -> (slot, v.Tast.ty)) binds in
|
||||||
(* The singleton is [in_loop]'s doing: it sits in this recursive group and
|
(* The singleton is [in_loop]'s doing: it sits in this recursive group and
|
||||||
is therefore monomorphic, and every other caller hands it a list. *)
|
is therefore monomorphic, and every other caller hands it a list. *)
|
||||||
|
|||||||
@ -99,4 +99,10 @@
|
|||||||
(Some v) (recur (+ i 1) (+ acc v))
|
(Some v) (recur (+ i 1) (+ acc v))
|
||||||
None acc)))
|
None acc)))
|
||||||
(println "") ; 0+1+2+3 = 6
|
(println "") ; 0+1+2+3 = 6
|
||||||
|
|
||||||
|
;; The bindings are sequential, as a let's are: the second initialiser reads
|
||||||
|
;; the first name. Only the initial values are; recur still rebinds at once.
|
||||||
|
(print (loop [a 1 b (+ a 10)]
|
||||||
|
(if (> a 3) b (recur (+ a 1) (+ b a)))))
|
||||||
|
(println "") ; 11+1+2+3 = 17
|
||||||
0)
|
0)
|
||||||
|
|||||||
@ -501,7 +501,7 @@ let () =
|
|||||||
rather than running out of stack. The swap line is the other — recur
|
rather than running out of stack. The swap line is the other — recur
|
||||||
rebinds every name at once, and interleaved writes would print 1. *)
|
rebinds every name at once, and interleaved writes would print 1. *)
|
||||||
outputs "loop and recur" "programs/recur.flan"
|
outputs "loop and recur" "programs/recur.flan"
|
||||||
"10\n2\n21\n8\n10000000\n64\n012\n0\n4\n012\n6\n";
|
"10\n2\n21\n8\n10000000\n64\n012\n0\n4\n012\n6\n17\n";
|
||||||
(* into. The count of pulls is the assertion a unit test cannot make: one
|
(* into. The count of pulls is the assertion a unit test cannot make: one
|
||||||
pass, one call per element per stage it reaches, and no intermediate
|
pass, one call per element per stage it reaches, and no intermediate
|
||||||
collection anywhere. The two show lines either side of it are the same
|
collection anywhere. The two show lines either side of it are the same
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user