我定义了以下模块来实现 matrix 类型:
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;;
但是,当我使用模块函数(
zeroes
、identity
、init
)声明矩阵并尝试打印它们时,只有组成它们的部分行被格式化,第一行的格式不正确。
例如我尝试过:
let empty = zeroes 3 5;;
let id = identity 4;;
let mat = init 5;;
print_matrix mat;;
print_matrix empty;;
print_matrix id;;
我得到了结果:
[ ]
[ ]
[ ]
[ ]
[ ]
[ 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 ]
去除代码中不必要的
;
和 ;;
标记,我们还可以强制实现您的 print_matrix
函数。鉴于您使用的是数组,这更有意义。
从数组转换为列表,然后再转换回来,以便您可以使用递归和模式匹配,这不仅效率低下,而且会使您的代码更难以理解。
module MatrixImplementation =
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 print_matrix {n; m; c} =
for i = 0 to n - 1 do
print_string "[";
for j = 0 to m - 1 do
Printf.printf " %d " c.(i).(j)
done;
print_string "]\n"
done
end
utop # MatrixImplementation.(init 3 |> print_matrix);;
[ 0 1 2 ]
[ 2 3 4 ]
[ 4 5 6 ]
- : unit = ()
注意:
print_string ""
实际上什么也不做。如果您实际上不需要执行任何操作,则只需返回 ()
(单位)即可。
另请注意,在
print_matrix
中,我在函数参数 (let print_matrix {n; m; c} =
) 中使用了模式匹配,以节省自己一些时间。这可以写成:
let print_matrix m =
for i = 0 to m.n - 1 do
print_string "[";
for j = 0 to m.m - 1 do
Printf.printf " %d " m.c.(i).(j)
done;
print_string "]\n"
done
我们可以利用
Array.iter
功能。
let print_matrix {n; m; c} =
Array.(
let print_row arr =
print_string "[";
arr |> iter (Printf.printf " %d ");
print_string "]\n"
in
c |> iter print_row
)
如果我们考虑您原来的方法,以下内容将解决它。
let rec print_row rl =
List.iter (Printf.printf " %2d ") rl
作为补充说明,我们可以使用
Format
模块为数组定义自定义格式化程序。
let pp_array
(type t) (module M : Stringable with type t = t)
?(sep = "; ")
?(start = "[|")
?(fin = "|]")
()
ppf
(arr : t array) =
Format.fprintf
ppf
"%s%s%s"
start
(arr |> Array.to_list |> List.map M.to_string |> String.concat sep)
fin
现在我们可以使用
Format.asprintf
来获取数组的字符串表示形式。
# Format.asprintf
"%a"
(pp_array
(module Int)
~sep: " "
~start: "[ "
~fin: " ]"
())
[|1; 2; 3|];;
- : string = "[ 1 2 3 ]"
查看我的模块的代码及其不正确的行为,问题不在于打印函数的定义方式(忽略@Chris在他的回答中建议的技巧),而是使用的模块:应该使用
Format
模块为了制作更复杂的打印输出(API参考),格式错误可能是由于fmt
字符串的参数造成的;对于更简单的打印,Printf
模块及其 printf
函数(相同的参数)更合适。
因此打印功能可能发生的变化如下:
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;
;;
(在这种情况下,类型定义
c
的字段matrix
(内容)是int list list
以避免转换)