在 OCaml 雖然有提供 forwhile 語法,但其實這兩個語法缺乏了 continuebreak 的功能,某種程度上在鼓勵你寫遞迴,當然你遞迴寫的嚇嚇叫,隨手一揮就能輕鬆寫出需要的遞迴結構,你可能完全不需要這個功能。

不過在某些狀況下,for, while 寫出來的程式易讀性可能較好,這時就不得不思考能不能對這兩個功能作抽象並補足缺乏的功能。

exception Continue
exception Break
 
let continue () = raise Continue
 
let break () = raise Break
 
let for_loop s e step ~f =
  let rec aux c =
    if not (c >= s && c < e) then
      ()
    else (
      try
        f c;
        aux (c + step)
      with
      | Continue -> aux (c + step)
      | Break -> ()
      | e -> raise e
    )
  in
  aux s
;;
 
let rec while_loop ~cond ~f =
  if cond () then (
    try
      f ();
      while_loop ~cond ~f
    with
    | Continue -> while_loop ~cond ~f
    | Break -> ()
    | e -> raise e
  )
;;

透過拋出例外的方式來模擬 continuebreak 的功能,這樣就可以在 for_loopwhile_loop 內中斷或繼續。

(* while loop *)
let () =
  let sum = ref 0 in
  let cond () = !sum < 100 in
  while_loop ~cond ~f:(fun _ ->
    let s = !sum in
    if s > 50 then
      break ()
    else if s = 25 then (
      sum := s + 26;
      continue ()
    ) else
      sum := s + 1);
  print_int !sum (* 51 *)
;;
 
(* for loop *)
let () =
  let sum = ref 0 in
  for_loop 0 10 1 ~f:(fun i ->
    let s = !sum in
    if i mod 2 = 1 then
      continue ()
    else if s > 10 then
      break ()
    else
      sum := s + i);
  print_int !sum (* 12 *)
;;