練習問題 8.7

リストに対する繰り返し iter を参考にして、配列要素に対して繰り返し処理を行う array_iter を定義しなさい。
(ヒント:配列の長さの求め方がわからなければ、長さを越えた要素アクセスで例外が発生することを利用しなさい)。

出力例

# array_iter;;
  - : ('a -> 'b) -> 'a array -> unit = <fun>

# array_iter (fun s -> print_string "Station: "; print_endline s)
    {|"Tokyo"; "Shinagawa"; "Shin-Yokohama"; "Nagoya"; "Kyoto"; "Shin-Osaka"|};;

Station: Tokyo
Station: Shinagawa
Station: Shin-Yokohama
Station: Nagoya
Station: Kyoto
Station: Shin-Osaka
- : unit = 0

参考

リストに対する繰り返し iter

(* iter リストの各要素に命令を表す関数を順に適用する *)
let rec iter f = function
    [] -> ()
    | a :: rest ->
            begin
                f a;
                iter f rest
            end;;

(* 駅名の入った文字列リストの内容を画面に表示する *)
iter (fun s -> print_string "Station: "; print_endline s)
["Tokyo"; "Shinagawa"; "Shin-Yokohama"; "Nagoya"; "Kyoto"; "Shin-Osaka"];;

解答

length 関数を使った場合

let array_iter f arr =
  let i = ref 0 and j = Array.length arr in
  while (!i < j) do
      f arr.(!i);
      i := !i + 1
  done
;;

例外処理を使った場合

let array_iter f arr =
  let i = ref 0 and j = ref true in
  while (!j = true) do
    try
      f arr.(!i);
      i := !i + 1
   with
     Invalid_argument "index out of bounds" -> j := false;
  done
;;

array_iter (fun s -> print_string "Station: "; print_endline s)
[|"Tokyo"; "Shinagawa"; "Shin-Yokohama"; "Nagoya"; "Kyoto"; "Shin-Osaka"|];;

最初、以下のような警告が出た。

Warning 52: Code should not depend on the actual values of
  this constructor's arguments. They are only for information
and may change in future versions. (See manual section 8.5)

これは、事前に以下の文を記述しておくと、回避できるみたい。

exception Invalid_argument of string;;