如何在 Bigarray 中的 GADT 上进行模式匹配?

How to pattern match on a GADT in Bigarray?

我们如何在 GADT 上进行模式匹配?在这种情况下,我在使用 Bigarray 的 GADT 时遇到了问题。更具体地说,代码

let print_layout v = match Bigarray.Genarray.layout v with
    | Bigarray.C_layout -> Printf.printf "C layout\n"
    | Bigarray.Fortran_layout -> Printf.printf "Fortran layout\n"

编译失败,出现错误信息

Error: This pattern matches values of type
         Bigarray.fortran_layout Bigarray.layout
       but a pattern was expected which matches values of type
         Bigarray.c_layout Bigarray.layout
       Type Bigarray.fortran_layout is not compatible with type
         Bigarray.c_layout 

它在抱怨 Bigarray.Fortran_layout 案例。如果我们查看 Bigarray 我们会看到

type c_layout = C_layout_typ
type fortran_layout = Fortran_layout_typ
type 'a layout =
    C_layout : c_layout layout
  | Fortran_layout : fortran_layout layout

所以,这是一个 GADT,我在模式匹配方面做错了。 print_layout 的工作版本是什么?

这是一个函数,returns 表示布局的字符串:

let layout_str : type l. l Bigarray.layout -> string = function
  | Bigarray.C_layout -> "C layout"
  | Bigarray.Fortran_layout -> "Fortran layout"

您可以使用它来定义您想要的功能

let print_layout v =
  Printf.printf "%s\n" (layout_str (Bigarray.Genarray.layout v))

对我有用:

$ ocaml
        OCaml version 4.02.1

# #load "bigarray.cma";;
# open Bigarray;;
# let fv = Genarray.create int32 Fortran_layout [| 0; 1; 2 |];;
val fv :
  (int32, Bigarray.int32_elt, Bigarray.fortran_layout) Bigarray.Genarray.t =
  <abstr>
# let cv = Genarray.create int32 C_layout [| 0; 1; 2 |];;
val cv : (int32, Bigarray.int32_elt, Bigarray.c_layout) Bigarray.Genarray.t = 
  <abstr>
# let layout_str : type l. l Bigarray.layout -> string = function
  | Bigarray.C_layout -> "C layout" 
  | Bigarray.Fortran_layout -> "Fortran layout";;
val layout_str : 'l Bigarray.layout -> string = <fun>
# let print_layout v =
  Printf.printf "%s\n" (layout_str (Bigarray.Genarray.layout v));;
val print_layout : ('a, 'b, 'c) Bigarray.Genarray.t -> unit = <fun>
# print_layout fv;;
Fortran layout
- : unit = ()
# print_layout cv;;
C layout
- : unit = ()
#

使用 gadts,您通常需要在进行通用模式匹配时添加注释(应该适用于一个类型的所有构造函数)。

这是做你想做的事情的正确方法:

let print_layout (type t) (v: (_,_,t) Bigarray.Genarray.t) =
  match Bigarray.Genarray.layout v with
  | Bigarray.C_layout -> Printf.printf "C layout\n"
  | Bigarray.Fortran_layout -> Printf.printf "Fortran layout\n"

注解引入了一个抽象类型t,它将成为布局类型。通过布局上的模式匹配,你会发现它实际上等于哪种布局类型。