Ocaml 在这种情况下我需要一个函子吗?

Ocaml 在这种情况下我需要一个函子吗?,ocaml,Ocaml,我在以下代码中使用: let build_data_32 v wid = let num = wid / 32 in let v' = Int32.of_int(v) in let rec aux lst vv w = match w with 0 -> lst | _ -> (BITSTRING { vv : 32 } ) :: ( aux lst (Int32.succ vv) (w-1)) in Bitstring.concat ( aux [] v

我在以下代码中使用:

let build_data_32 v wid =
  let num = wid / 32 in
  let v' = Int32.of_int(v) in
  let rec aux lst vv w = match w with
    0 -> lst
  | _ -> (BITSTRING { vv : 32 } ) :: ( aux lst (Int32.succ vv) (w-1)) in
  Bitstring.concat ( aux [] v' num ) ;;
请注意,当您有
位字符串{vv:32}
该vv应为Int32值。我想将这个函数推广到不同宽度的位字符串;也就是说,我想创建一个build_data_n函数,其中位字符串将使用
bitstring{vv:n}
构造

然而,这里的问题是,如果n小于32,则上面使用的succ函数将只是int类型的succ。如果它大于32,则将是Int64。succ与上面的
let v'=Int32.of_int(v)in
行中的相同问题-对于小于32的值,它将是:
let v'=v in
,而对于大于32的值,则为:
let v'=Int64.of_int(v)in


在这种情况下,函子可以方便地推广这个函数吗?如果可以,我该如何设置它?(如果还有其他不需要函子的方法,也很高兴知道)

有几种方法可用。一种是使用函子,类似于以下内容:

(* The signature a module needs to match for use below *)
module type S = sig
  type t
  val succ : t -> t
  val of_int : int -> t
end

(* The functor *)
module Make(M : S) = struct
  (* You could "open M" here if you wanted to save some typing *)
  let build_data v =
    M.succ (M.of_int v)
end

(* Making modules with the functor *)
module Implementation32 = Make(Int32)
module Implementation64 = Make(Int64)

let foo32 = Implementation32.build_data 12
let foo64 = Implementation64.build_data 12
另一种方法是将数据类型包装到记录中:

(* A record to hold the relevant functions *)
type 'a wrapper_t = { x : 'a; succ : 'a -> 'a }

(* Use values of type 'a wrapper_t in *)
let build_data v =
  v.succ v.x

(* Helper function to create 'a wrapper_t values *)
let make_int32_wrapper x = { x = Int32.of_int x; succ = Int32.succ }
let make_int64_wrapper x = { x = Int64.of_int x; succ = Int64.succ }

(* Do something with a wrapped int32 *)
let foo32 = build_data (make_int32_wrapper 12)
let foo64 = build_data (make_int64_wrapper 12)
最后,如果您使用的是OCaml 3.12.0或更高版本,则可以使用一流的模块:

(* You can use the module type S from the first example here *)

let build_data (type s) m x =
  let module M = (val m : S with type t = s) in
  M.succ x

let int32_s = (module Int32 : S with type t = Int32.t)
let int64_s = (module Int64 : S with type t = Int64.t)

let foo32 = build_data int32_s 12l
let foo64 = build_data int64_s 12L

这些方法中的每一种都可以混合和匹配。您还可以将值包装在变量类型或对象中以获得类似的结果。

使用
位字符串{vv:n}
,即使用运行时指定的字段长度,
vv
的类型不能依赖于
n
,因为它不再是编译时常量,因此,
vv
被迫
int64

坦白说,我认为你的解决方案太复杂了,无法回答一个潜在的初学者问题。我知道一流的模块是新的、热门的和有趣的,但我们应该首先支持简单性。在这种情况下,如果没有ygrek解释的位串干扰,一个简单的解决方案是将
of int
succ
作为
build\u data
函数的参数传递。我觉得很不安的是,您提供了三个包含大量样板文件的解决方案,但不是这一个。@gasche:是的,将of int和succ函数作为参数传入可能是最简单的。。。除了ygrek解释的问题。不过,看到一流的模块解决方案还是很有趣的。那么,你是说如果你对字段长度(上面的n)使用一个变量,那么vv将始终被强制为int64吗?啊,是的,我明白你的意思了:#让我们得到#bitstring v n=bitstring{v:n};;val get_bitstring:int64->int->bitstring.bitstring=