Search code examples
functional-programmingocaml

Why the same function prints different output?


I have defined the following module to implement a matrix type:

module MatrixImplementation: MatrixADT.MatrixInterface =
  struct
    type 'a matrix = {n: int; m: int; c: 'a array array};;
    let zeroes n m = {n= n; m= m; c= Array.make_matrix n m 0};;
    let identity n =
      let m = zeroes n n
      in for i = 0 to (n-1) do
        m.c.(i).(i) <- 1
      done;
      (m);
    ;;
    let init n =
      let m = zeroes n n
        in for i = 0 to (n-1)do
          for j = 0 to (n-1) do
            m.c.(i).(j) <- (n-1) * i + j;
          done;
        done;
        (m);
    ;;
    (* . . . *)
    let rec print_row  rl =
      match rl with
      | [] -> print_string("");
      | v::cl -> Format.printf "%2d " v; print_row cl;
    ;;
    let rec print_matrix m =
      match Array.to_list m.c with
      | [] -> print_string("");
      | r::rl ->
        print_string "[ ";
        print_row (Array.to_list r);
        print_string "]\n";
        print_matrix {n= ((m.n)-1); m= (m.m); c= Array.of_list rl};
    ;;
  end;;

However when I declare matrices using the module functions (zeroes, identity, init) and try to print them, only part of the lines that compose them are formatted, the first lines are not correctly formatted.

For instance i tried with:

let empty = zeroes 3 5;;
let id = identity 4;;
let mat = init 5;;

print_matrix mat;;
print_matrix empty;;
print_matrix id;;

And I got it as a result:

[ ]
[ ]
[ ]
[ ]
[ ]
[  0  1  2  3  4  4  5  6  7  8  8  9 10 11 12 12 13 14 15 16 16 17 18 19 20  0  0  0  0  0 ]
[  0  0  0  0  0 ]
[  0  0  0  0  0 ]
[  1  0  0  0 ]
[  0  1  0  0 ]
[  0  0  1  0 ]
[  0  0  0  1 ]

Solution

  • Reviewing the code of my module and its incorrect behavior, the problem is not the way the print functions are defined (leaving out the tricks suggested by @Chris in his answer), but the module used: the Format module should be used to make more complex printouts (API reference), the formatting error is probably due to the arguments of the fmt string; for simpler printing, the Printf module and its printf function (same arguments) are more suitable.

    Therefore a possible change to the printing functions is as follows:

    let rec print_row = function
        | [] -> ()
        | c::cl -> Printf.printf "%2d " c; print_row cl;
    and print_matrix m =
        match m.c with
        | [] -> ()
        | rows ->
          for i= 0 to (List.length rows)-1 do
            print_string("[ ");
            print_row (List.nth rows i);
            print_string("]\n");
          done;
    ;;
    

    (In this case the field c (content) of type definition matrix is int list list to avoid conversions)