Bobbyrogers
Bobbyrogers

Reputation: 302

If statements end function early if false in OCaml

Assuming pos_of_xy (x, y) n is already defined to return an int, this code segment exits once one of the if statements returns false as if they were nested. I need them all to run regardless of the previous if statements. I'm not sure what I am forgetting.

let final = ref [] in begin
  if x < (size-1) then let pos = pos_of_xy (x+1, y) size in final := pos::!final;
  if y < (size-1) then let pos = pos_of_xy (x, y+1) size in final := pos::!final;
  if y > 0 then let pos = pos_of_xy (x, y-1) size in final := pos::!final;
  if x > 0 then let pos = pos_of_xy (x-1, y) size in final := pos::!final;
end;

Upvotes: 2

Views: 456

Answers (2)

newacct
newacct

Reputation: 122429

As Jeffrey Scofield said, let has lower precedence than if. So it's as if you wrote:

let final = ref [] in begin
  if x < (size-1) then (let pos = pos_of_xy (x+1, y) size in (final := pos::!final;
  (if y < (size-1) then (let pos = pos_of_xy (x, y+1) size in (final := pos::!final;
  (if y > 0 then (let pos = pos_of_xy (x, y-1) size in (final := pos::!final;
  (if x > 0 then (let pos = pos_of_xy (x-1, y) size in (final := pos::!final;)))))))))))
end;

You can look at the table of precedences here (scroll up a little). As you can see, if has higher precedence than ;, which has higher precedence than let.

Upvotes: 1

Jeffrey Scofield
Jeffrey Scofield

Reputation: 66808

One way of describing the problem is that let is stronger than if. A let takes a sequence of statements after in, and your subsequent ifs are treated as part of this sequence. Things should work if you parenthesize each let:

if x < size - 1 then
    (let pos = pos_of_xy (x + 1, y) size in final := pos :: !final);

Or you could do without the let:

if x < size -1 then final := pos_of_xy (x + 1, y) size :: !final;

As a side comment, the code might look even nicer to an FP progammer if you wrote in a more functional style (without the mutable value).

Update

Here's a quick sketch of a more functional way to calculate your list:

let good (x, y) = x >= 0 && x < size && y >= 0 && y < size in
let topos (x, y) = pos_of_xy (x, y) size in
let goodxy =
    List.filter good [(x + 1, y); (x, y + 1); (x - 1, y); (x, y - 1)] in
List.map topos goodxy

Upvotes: 6

Related Questions