ocaml: && / || short-circuit fix + bfs_grid.ml baseline (5x5 grid, dist 8)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 22s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 22s
Before: `:op` handler always evaluated both operands before dispatching
to ocaml-eval-op. For pure binops that's fine, but `&&` / `||` MUST
short-circuit:
if nr >= 0 && grid.(nr).(nc) = 0 then ...
When nr = -1, real OCaml never evaluates `grid.(-1)`. Our evaluator
did, and crashed with "nth: list/string and number".
Fix: special-case `&&` and `||` in :op dispatch, mirroring the same
pattern already used for `:=` and `<-`. Evaluate lhs, branch on it,
and only evaluate rhs when needed.
Latent since baseline 1 — earlier programs never triggered it because
the rhs was unconditionally safe.
bfs_grid.ml: shortest path through a 5x5 grid with walls. Standard
BFS using Queue.{push,pop,is_empty} + Array.init for the 2D distance
matrix. Path 0,0 -> ... -> 4,4 has length 8. 155 baseline programs
total.
This commit is contained in:
42
lib/ocaml/baseline/bfs_grid.ml
Normal file
42
lib/ocaml/baseline/bfs_grid.ml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
let h = 5
|
||||||
|
let w = 5
|
||||||
|
|
||||||
|
let grid = [|
|
||||||
|
[| 0; 0; 1; 0; 0 |];
|
||||||
|
[| 1; 0; 1; 0; 1 |];
|
||||||
|
[| 0; 0; 0; 0; 0 |];
|
||||||
|
[| 0; 1; 1; 1; 0 |];
|
||||||
|
[| 0; 0; 0; 0; 0 |]
|
||||||
|
|]
|
||||||
|
|
||||||
|
let step dist q r c nr nc =
|
||||||
|
if nr >= 0 && nr < h && nc >= 0 && nc < w
|
||||||
|
&& grid.(nr).(nc) = 0 && dist.(nr).(nc) = -1 then begin
|
||||||
|
dist.(nr).(nc) <- dist.(r).(c) + 1;
|
||||||
|
Queue.push (nr * 10 + nc) q
|
||||||
|
end
|
||||||
|
|
||||||
|
let bfs sr sc tr tc =
|
||||||
|
let dist = Array.init h (fun _ -> Array.make w (-1)) in
|
||||||
|
let q = Queue.create () in
|
||||||
|
dist.(sr).(sc) <- 0;
|
||||||
|
Queue.push (sr * 10 + sc) q;
|
||||||
|
let go = ref true in
|
||||||
|
while !go do
|
||||||
|
if Queue.is_empty q then go := false
|
||||||
|
else if dist.(tr).(tc) <> -1 then go := false
|
||||||
|
else begin
|
||||||
|
let rc = Queue.pop q in
|
||||||
|
let r = rc / 10 in
|
||||||
|
let c = rc mod 10 in
|
||||||
|
step dist q r c (r - 1) c;
|
||||||
|
step dist q r c (r + 1) c;
|
||||||
|
step dist q r c r (c - 1);
|
||||||
|
step dist q r c r (c + 1)
|
||||||
|
end
|
||||||
|
done;
|
||||||
|
dist.(tr).(tc)
|
||||||
|
|
||||||
|
;;
|
||||||
|
|
||||||
|
bfs 0 0 4 4
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
"balance.ml": 3,
|
"balance.ml": 3,
|
||||||
"base_n.ml": 17,
|
"base_n.ml": 17,
|
||||||
"bfs.ml": 6,
|
"bfs.ml": 6,
|
||||||
|
"bfs_grid.ml": 8,
|
||||||
"btree.ml": 39,
|
"btree.ml": 39,
|
||||||
"brainfuck.ml": 75,
|
"brainfuck.ml": 75,
|
||||||
"bsearch.ml": 7,
|
"bsearch.ml": 7,
|
||||||
|
|||||||
@@ -657,6 +657,14 @@
|
|||||||
(error
|
(error
|
||||||
(str "ocaml-eval: <- expects a field-access lhs, got "
|
(str "ocaml-eval: <- expects a field-access lhs, got "
|
||||||
(ocaml-tag-of lhs-ast)))))))
|
(ocaml-tag-of lhs-ast)))))))
|
||||||
|
;; && and || short-circuit — must NOT evaluate rhs when
|
||||||
|
;; lhs already decides. Mirrors real OCaml semantics.
|
||||||
|
((= op "&&")
|
||||||
|
(let ((lhs (ocaml-eval (nth ast 2) env)))
|
||||||
|
(if lhs (ocaml-eval (nth ast 3) env) false)))
|
||||||
|
((= op "||")
|
||||||
|
(let ((lhs (ocaml-eval (nth ast 2) env)))
|
||||||
|
(if lhs true (ocaml-eval (nth ast 3) env))))
|
||||||
(else
|
(else
|
||||||
(ocaml-eval-op op
|
(ocaml-eval-op op
|
||||||
(ocaml-eval (nth ast 2) env)
|
(ocaml-eval (nth ast 2) env)
|
||||||
|
|||||||
@@ -407,6 +407,19 @@ _Newest first._
|
|||||||
binary search tree (`type 'a tree = Leaf | Node of 'a * 'a tree *
|
binary search tree (`type 'a tree = Leaf | Node of 'a * 'a tree *
|
||||||
'a tree`) with insert + in-order traversal. Tests parametric ADT,
|
'a tree`) with insert + in-order traversal. Tests parametric ADT,
|
||||||
recursive match, List.append, List.fold_left.
|
recursive match, List.append, List.fold_left.
|
||||||
|
- 2026-05-10 Phase 5.1 — `&&` / `||` short-circuit fix + bfs_grid.ml
|
||||||
|
baseline (BFS shortest path on 5×5 grid with walls, dist 8). The
|
||||||
|
evaluator's `:op` handler was evaluating BOTH sides of `&&`/`||`
|
||||||
|
before dispatching, mismatching OCaml's left-to-right
|
||||||
|
short-circuit semantics. This was invisible in earlier baselines
|
||||||
|
because their rhs was always safe regardless of lhs, but a guard
|
||||||
|
like `if nr >= 0 && grid.(nr).(nc) = 0 then …` crashes with
|
||||||
|
"nth: list/string and number" when nr = -1 because `grid.(-1)`
|
||||||
|
still gets evaluated. Fix: dispatch `&&` and `||` specially in
|
||||||
|
`:op` to evaluate lhs first and only evaluate rhs if needed.
|
||||||
|
Bug latent since baseline 1; surfaced by bfs_grid with bounds-
|
||||||
|
checked grid access. bfs_grid optimal path 0→1→1→2→2→3→3→3→4 of
|
||||||
|
weighted length 8. 155 baseline programs total.
|
||||||
- 2026-05-10 Phase 5.1 — tarjan_scc.ml baseline (Tarjan's
|
- 2026-05-10 Phase 5.1 — tarjan_scc.ml baseline (Tarjan's
|
||||||
strongly-connected components on 8-node digraph → 4 SCCs).
|
strongly-connected components on 8-node digraph → 4 SCCs).
|
||||||
Graph: 0→1→2→0 (cycle) plus 2→3, 3→4, 4→5→6→4 (cycle), 4→7.
|
Graph: 0→1→2→0 (cycle) plus 2→3, 3→4, 4→5→6→4 (cycle), 4→7.
|
||||||
|
|||||||
Reference in New Issue
Block a user