为什么相同的函数打印不同的输出?

问题描述 投票:0回答:2

我定义了以下模块来实现 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 ]
functional-programming ocaml
2个回答
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 ]"

0
投票

查看我的模块的代码及其不正确的行为,问题不在于打印函数的定义方式(忽略@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
以避免转换)

© www.soinside.com 2019 - 2024. All rights reserved.